diff --git a/bin/baseset/openttd.grf b/bin/baseset/openttd.grf index ea5f55ce1d..111004c175 100644 Binary files a/bin/baseset/openttd.grf and b/bin/baseset/openttd.grf differ diff --git a/docs/landscape.html b/docs/landscape.html index c8ac686c07..65fbee7db5 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -98,6 +98,38 @@ +
  • m4:
    + + Road roadtype. Used for all tiles with road (road, station, tunnelbridge). + +
  • +
  • m8:
    + + Tram roadtype. Used for all tiles with road (road, station, tunnelbridge). + +
  • +
  • m8:
    + + +
  • m7:
    Animation frame/state. Used for houses, industries, objects and stations.
  • @@ -108,7 +140,7 @@ - + @@ -542,21 +574,10 @@
    ClassMeaning & details of encodingMeaning & details of encoding
    0
    • m2: Index into the array of towns (owning town for town roads; closest town otherwise, INVALID_TOWN if there is no town or we are creating a town)
    • -
    • m7 bit 5 set = on snow or desert
    • -
    • m7 bits 7..6: present road types - - - - - - - - - - -
      bit 0  normal road
      bit 1  tram
      -
    • m3 bits 7..4: owner of road type 1 (tram); OWNER_NONE (10) is stored as OWNER_TOWN (0F) +
    • m4 bits 5..0: Roadtype
    • +
    • m7 bit 5 set = on snow or desert
    • +
    • m8 bits 11..6: Tramtype
    • m5 bits 7 clear: road or level-crossing
      • m6 bits 5..3: @@ -870,6 +891,7 @@
      • m3 bits 7..4: persistent random data for railway stations/waypoints and airports)
      • m3 bits 7..4: owner of tram tracks (road stop)
      • m4: custom station id; 0 means standard graphics
      • +
      • m4: Roadtype for road stops
      • m5: graphics index (range from 0..255 for each station type): @@ -985,8 +1007,8 @@
      • m6 bit 2: pbs reservation state for railway stations/waypoints
      • m7 bits 4..0: owner of road (road stops)
      • -
      • m7 bits 7..6: present road types (road stops)
      • m7: animation frame (railway stations/waypoints, airports)
      • +
      • m8 bits 11..6: Tramtype
      • m8 bits 5..0: track type for railway stations/waypoints
      • @@ -1563,6 +1585,9 @@
      • m5 bit 4: pbs reservation state for railway (tunnel only)
      • m5 bit 7 clear: tunnel entrance/exit
      • +
      • m4: Roadtype
      • +
      • m5 bit 4: pbs reservation state for railway
      • +
      • m5 bits 7 clear: tunnel entrance/exit
      • m5 bit 7 set: bridge ramp
        • m6 bits 5..2: bridge type: @@ -1729,7 +1754,7 @@
        • m7 bits 4..0: owner of road
        • m7 bit 5 set = on snow or desert
        • -
        • m7 bits 7..6: present road types for road
        • +
        • m8 bits 11..6: Tramtype
        • m8 bits 5..0: track type for railway
        • m8 bits 11..6 = secondary track type for railway (used for bridge-bypassing track when two parallel tracks on custom bridge head)
        diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html index cd5fb3c9e2..f13ff1c9c0 100644 --- a/docs/landscape_grid.html +++ b/docs/landscape_grid.html @@ -145,11 +145,11 @@ the array so you can quickly see what is used and what is not.
      • - + - - + + @@ -161,8 +161,8 @@ the array so you can quickly see what is used and what is not. - - + + @@ -171,11 +171,11 @@ the array so you can quickly see what is used and what is not. - + - - + + @@ -239,11 +239,11 @@ the array so you can quickly see what is used and what is not. - + - - + + @@ -359,11 +359,11 @@ the array so you can quickly see what is used and what is not. - - + + - - + + @@ -372,11 +372,11 @@ the array so you can quickly see what is used and what is not. - + - + diff --git a/media/extra_grf/openttdgui.nfo b/media/extra_grf/openttdgui.nfo index d0fbba0e70..b01a70f795 100644 --- a/media/extra_grf/openttdgui.nfo +++ b/media/extra_grf/openttdgui.nfo @@ -7,7 +7,7 @@ // See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . // -1 * 0 0C "OpenTTD GUI graphics" - -1 * 3 05 15 \b 179 // OPENTTD_SPRITE_COUNT + -1 * 3 05 15 \b 184 // OPENTTD_SPRITE_COUNT -1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal @@ -187,3 +187,8 @@ -1 sprites/openttdgui_group_livery.png 8bpp 21 0 20 20 0 0 normal -1 sprites/openttdgui_group_livery.png 8bpp 42 0 20 20 0 0 normal -1 sprites/openttdgui_group_livery.png 8bpp 63 0 20 20 0 0 normal + -1 sprites/openttdgui_build_tram.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_road.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_road.png 8bpp 24 0 32 32 0 0 normal + -1 sprites/openttdgui_convert_tram.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_tram.png 8bpp 24 0 32 32 0 0 normal diff --git a/media/extra_grf/openttdgui_build_tram.png b/media/extra_grf/openttdgui_build_tram.png new file mode 100644 index 0000000000..d9af8effe2 Binary files /dev/null and b/media/extra_grf/openttdgui_build_tram.png differ diff --git a/media/extra_grf/openttdgui_convert_road.png b/media/extra_grf/openttdgui_convert_road.png new file mode 100644 index 0000000000..9218e77054 Binary files /dev/null and b/media/extra_grf/openttdgui_convert_road.png differ diff --git a/media/extra_grf/openttdgui_convert_tram.png b/media/extra_grf/openttdgui_convert_tram.png new file mode 100644 index 0000000000..d4a43e7cb7 Binary files /dev/null and b/media/extra_grf/openttdgui_convert_tram.png differ diff --git a/media/extra_grf/tramtracks.nfo b/media/extra_grf/tramtracks.nfo index 5a078194b9..89c3e5c6ea 100644 --- a/media/extra_grf/tramtracks.nfo +++ b/media/extra_grf/tramtracks.nfo @@ -7,7 +7,7 @@ // See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . // -1 * 0 0C "Tram track graphics by PikkaBird" - -1 * 3 05 0B 71 + -1 * 3 05 0B 77 -1 sprites/tramtracks.png 8bpp 18 8 20 13 0 4 normal -1 sprites/tramtracks.png 8bpp 50 8 20 13 0 4 normal -1 sprites/tramtracks.png 8bpp 82 8 64 36 -18 -8 normal @@ -121,3 +121,9 @@ -1 sprites/tramtracks.png 8bpp 722 696 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 776 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 776 64 39 -31 -8 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 0 0 64 31 -31 0 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 80 0 62 64 2 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 158 0 64 31 -31 0 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 238 0 62 64 -62 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 318 0 62 64 -62 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 398 0 62 64 2 -49 normal diff --git a/media/extra_grf/tramtracks_bare_depot.png b/media/extra_grf/tramtracks_bare_depot.png new file mode 100644 index 0000000000..d45bcff41e Binary files /dev/null and b/media/extra_grf/tramtracks_bare_depot.png differ diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index dbd1e67191..c2f574f285 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -604,6 +604,7 @@ + @@ -638,6 +639,7 @@ + @@ -1006,6 +1008,7 @@ + @@ -1144,6 +1147,7 @@ + @@ -1210,6 +1214,7 @@ + @@ -1283,6 +1288,7 @@ + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 187ef0e7c0..d6a6a4aba1 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -906,6 +906,9 @@ Header Files + + Header Files + Header Files @@ -1008,6 +1011,9 @@ Header Files + + Header Files + Header Files @@ -2112,6 +2118,9 @@ Tables + + Tables + Tables @@ -2526,6 +2535,9 @@ Script API + + Script API + Script API @@ -2724,6 +2736,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2943,6 +2958,9 @@ NewGRF + + NewGRF + NewGRF diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 2bd1670b37..130fe69f8d 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -604,6 +604,7 @@ + @@ -638,6 +639,7 @@ + @@ -1006,6 +1008,7 @@ + @@ -1144,6 +1147,7 @@ + @@ -1210,6 +1214,7 @@ + @@ -1283,6 +1288,7 @@ + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index 187ef0e7c0..d6a6a4aba1 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -906,6 +906,9 @@ Header Files + + Header Files + Header Files @@ -1008,6 +1011,9 @@ Header Files + + Header Files + Header Files @@ -2112,6 +2118,9 @@ Tables + + Tables + Tables @@ -2526,6 +2535,9 @@ Script API + + Script API + Script API @@ -2724,6 +2736,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2943,6 +2958,9 @@ NewGRF + + NewGRF + NewGRF diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index cffc03b69d..b22761c16f 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -604,6 +604,7 @@ + @@ -638,6 +639,7 @@ + @@ -1006,6 +1008,7 @@ + @@ -1144,6 +1147,7 @@ + @@ -1210,6 +1214,7 @@ + @@ -1283,6 +1288,7 @@ + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index 187ef0e7c0..d6a6a4aba1 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -906,6 +906,9 @@ Header Files + + Header Files + Header Files @@ -1008,6 +1011,9 @@ Header Files + + Header Files + Header Files @@ -2112,6 +2118,9 @@ Tables + + Tables + Tables @@ -2526,6 +2535,9 @@ Script API + + Script API + Script API @@ -2724,6 +2736,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2943,6 +2958,9 @@ NewGRF + + NewGRF + NewGRF diff --git a/source.list b/source.list index 2dc1659aec..d38e722188 100644 --- a/source.list +++ b/source.list @@ -292,6 +292,7 @@ newgrf_industrytiles.h newgrf_object.h newgrf_properties.h newgrf_railtype.h +newgrf_roadtype.h newgrf_sound.h newgrf_spritegroup.h newgrf_station.h @@ -326,6 +327,7 @@ rail.h rail_gui.h rail_type.h rev.h +road.h road_cmd.h road_func.h road_gui.h @@ -722,6 +724,7 @@ table/pricebase.h table/railtypes.h table/road_land.h table/roadveh_movement.h +table/roadtypes.h ../objs/settings/table/settings.h table/sprites.h table/station_land.h @@ -878,6 +881,7 @@ script/api/script_order.hpp script/api/script_rail.hpp script/api/script_railtypelist.hpp script/api/script_road.hpp +script/api/script_roadtypelist.hpp script/api/script_sign.hpp script/api/script_signlist.hpp script/api/script_station.hpp @@ -946,6 +950,7 @@ script/api/script_order.cpp script/api/script_rail.cpp script/api/script_railtypelist.cpp script/api/script_road.cpp +script/api/script_roadtypelist.cpp script/api/script_sign.cpp script/api/script_signlist.cpp script/api/script_station.cpp @@ -1034,6 +1039,7 @@ newgrf_industries.cpp newgrf_industrytiles.cpp newgrf_object.cpp newgrf_railtype.cpp +newgrf_roadtype.cpp newgrf_sound.cpp newgrf_spritegroup.cpp newgrf_station.cpp diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index f5f5904c09..41a8420853 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -62,6 +62,7 @@ #include "../script/api/ai/ai_rail.hpp.sq" #include "../script/api/ai/ai_railtypelist.hpp.sq" #include "../script/api/ai/ai_road.hpp.sq" +#include "../script/api/ai/ai_roadtypelist.hpp.sq" #include "../script/api/ai/ai_sign.hpp.sq" #include "../script/api/ai/ai_signlist.hpp.sq" #include "../script/api/ai/ai_station.hpp.sq" @@ -167,6 +168,7 @@ void AIInstance::RegisterAPI() SQAIRail_Register(this->engine); SQAIRailTypeList_Register(this->engine); SQAIRoad_Register(this->engine); + SQAIRoadTypeList_Register(this->engine); SQAISign_Register(this->engine); SQAISignList_Register(this->engine); SQAIStation_Register(this->engine); diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 6e71c5af32..f687fec99a 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -21,6 +21,7 @@ #include "tracerestrict.h" #include "core/random_func.hpp" #include "vehiclelist.h" +#include "road.h" #include "table/strings.h" @@ -75,6 +76,9 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) } case VEH_ROAD: + /* make sure the roadtypes are compatible */ + if ((GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes & GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes) == ROADTYPES_NONE) return false; + /* make sure that we do not replace a tram with a normal road vehicles or vice versa */ if (HasBit(e_from->info.misc_flags, EF_ROAD_TRAM) != HasBit(e_to->info.misc_flags, EF_ROAD_TRAM)) return false; break; diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index c00d97b91e..a1a152cf69 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -14,6 +14,7 @@ #include "vehicle_gui.h" #include "newgrf_engine.h" #include "rail.h" +#include "road.h" #include "strings_func.h" #include "window_func.h" #include "autoreplace_func.h" @@ -24,6 +25,7 @@ #include "settings_func.h" #include "core/geometry_func.hpp" #include "rail_gui.h" +#include "road_gui.h" #include "widgets/dropdown_func.h" #include "widgets/autoreplace_widget.h" @@ -86,6 +88,7 @@ class ReplaceVehicleWindow : public Window { bool descending_sort_order; ///< Order of sorting vehicles. bool show_hidden_engines; ///< Whether to show the hidden engines. RailType sel_railtype; ///< Type of rail tracks selected. #INVALID_RAILTYPE to show all. + RoadType sel_roadtype; ///< Type of road selected. #INVALID_ROADTYPE to show all. Scrollbar *vscroll[2]; /** @@ -127,7 +130,21 @@ class ReplaceVehicleWindow : public Window { FOR_ALL_ENGINES_OF_TYPE(e, type) { if (!draw_left && !this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; - if (type == VEH_TRAIN && !this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains + switch (type) { + case VEH_TRAIN: + if (!this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains + break; + + case VEH_ROAD: + if (draw_left && this->sel_roadtype != INVALID_ROADTYPE) { + /* Ensure that the roadtype is specific to the selected one */ + if (e->u.road.roadtype != this->sel_roadtype) continue; + } + break; + + default: + break; + } if (draw_left) { const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); @@ -210,6 +227,7 @@ public: ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) { this->sel_railtype = INVALID_RAILTYPE; + this->sel_roadtype = INVALID_ROADTYPE; this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) this->engines[0].ForceRebuild(); this->engines[1].ForceRebuild(); @@ -229,6 +247,11 @@ public: widget->SetLowered(this->show_hidden_engines); this->FinishInitNested(vehicletype); + if (vehicletype == VEH_TRAIN || vehicletype == VEH_ROAD) { + widget = this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + widget->tool_tip = STR_REPLACE_HELP_RAILTYPE + vehicletype; + } + this->sort_criteria = _engine_sort_last_criteria[vehicletype]; this->descending_sort_order = _engine_sort_last_order[vehicletype]; this->owner = _local_company; @@ -287,13 +310,28 @@ public: break; } - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: { Dimension d = {0, 0}; - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { - const RailtypeInfo *rti = GetRailTypeInfo(rt); - /* Skip rail type if it has no label */ - if (rti->label == 0) continue; - d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + switch (this->window_number) { + case VEH_TRAIN: + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + const RailtypeInfo *rti = GetRailTypeInfo(rt); + /* Skip rail type if it has no label */ + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + break; + + case VEH_ROAD: + for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + /* Skip road type if it has no label */ + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + break; + + default: NOT_REACHED(); } d.width += padding.width; d.height += padding.height; @@ -409,9 +447,18 @@ public: * or The selected vehicle has no replacement set up */ this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, this->sel_engine[0] == INVALID_ENGINE || !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)); - if (this->window_number == VEH_TRAIN) { - /* Show the selected railtype in the pulldown menu */ - this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : GetRailTypeInfo(sel_railtype)->strings.replace_text; + switch (this->window_number) { + case VEH_TRAIN: + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : GetRailTypeInfo(sel_railtype)->strings.replace_text; + break; + + case VEH_ROAD: + /* Show the selected roadtype in the pulldown menu */ + this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_roadtype == INVALID_ROADTYPE ? STR_REPLACE_ALL_ROADTYPE : GetRoadTypeInfo(sel_roadtype)->strings.replace_text; + break; + + default: break; } this->DrawWidgets(); @@ -472,8 +519,16 @@ public: break; } - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu - ShowDropDownList(this, GetRailTypeDropDownList(true, true), sel_railtype, WID_RV_TRAIN_RAILTYPE_DROPDOWN); + case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: // Rail/roadtype selection dropdown menu + switch (this->window_number) { + case VEH_TRAIN: + ShowDropDownList(this, GetRailTypeDropDownList(true, true), sel_railtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + break; + + case VEH_ROAD: + ShowDropDownList(this, GetRoadTypeDropDownList(RTTB_ROAD | RTTB_TRAM, true, true), sel_roadtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + break; + } break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length @@ -533,10 +588,25 @@ public: } break; - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { - RailType temp = (RailType)index; - if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything - sel_railtype = temp; + case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: + switch (this->window_number) { + case VEH_TRAIN: { + RailType temp = (RailType)index; + if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything + sel_railtype = temp; + break; + } + + case VEH_ROAD: { + RoadType temp = (RoadType)index; + if (temp == sel_roadtype) return; // we didn't select a new one. No need to change anything + sel_roadtype = temp; + break; + } + + default: NOT_REACHED(); + } + /* Reset scrollbar positions */ this->vscroll[0]->SetPosition(0); this->vscroll[1]->SetPosition(0); @@ -546,7 +616,6 @@ public: this->reset_sel_engine = true; this->SetDirty(); break; - } case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN: { this->replace_engines = index != 0; @@ -603,7 +672,7 @@ static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN), SetDataTip(STR_BLACK_STRING, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), @@ -648,6 +717,64 @@ static WindowDesc _replace_rail_vehicle_desc( _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) ); +static const NWidgetPart _nested_replace_road_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_VEHICLES_IN_USE, STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES, STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(NWID_VERTICAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 1), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_RV_SHOW_HIDDEN_ENGINES), SetDataTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_road_vehicle_desc( + WDP_AUTO, "replace_vehicle_road", 500, 140, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_road_vehicle_widgets, lengthof(_nested_replace_road_vehicle_widgets) +); + static const NWidgetPart _nested_replace_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), @@ -710,5 +837,11 @@ static WindowDesc _replace_vehicle_desc( void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype) { DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype); - new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g); + WindowDesc *desc; + switch (vehicletype) { + case VEH_TRAIN: desc = &_replace_rail_vehicle_desc; break; + case VEH_ROAD: desc = &_replace_road_vehicle_desc; break; + default: desc = &_replace_vehicle_desc; break; + } + new ReplaceVehicleWindow(desc, vehicletype, id_g); } diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index da513470b2..2d4c641d20 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -13,6 +13,7 @@ #include "error.h" #include "command_func.h" #include "rail.h" +#include "road.h" #include "strings_func.h" #include "window_func.h" #include "sound_func.h" @@ -410,11 +411,25 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo Money infra_cost = 0; switch (transport_type) { - case TRANSPORT_ROAD: - infra_cost = (bridge_len + 2) * _price[PR_BUILD_ROAD] * 2; + case TRANSPORT_ROAD: { /* In case we add a new road type as well, we must be aware of those costs. */ - if (IsBridgeTile(start)) infra_cost *= CountBits(GetRoadTypes(start) | (RoadTypes)road_rail_type); + RoadType road_rt = INVALID_ROADTYPE; + RoadType tram_rt = INVALID_ROADTYPE; + if (IsBridgeTile(start)) { + road_rt = GetRoadTypeRoad(start); + tram_rt = GetRoadTypeTram(start); + } + if (RoadTypeIsRoad((RoadType)road_rail_type)) { + road_rt = (RoadType)road_rail_type; + } else { + tram_rt = (RoadType)road_rail_type; + } + + if (road_rt != INVALID_ROADTYPE) infra_cost += (bridge_len + 2) * 2 * RoadBuildCost(road_rt); + if (tram_rt != INVALID_ROADTYPE) infra_cost += (bridge_len + 2) * 2 * RoadBuildCost(tram_rt); + break; + } case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost((RailType)road_rail_type); break; default: break; } diff --git a/src/bridge_map.h b/src/bridge_map.h index b315ac8ecd..cd672e8f0a 100644 --- a/src/bridge_map.h +++ b/src/bridge_map.h @@ -131,11 +131,11 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, D SetTileOwner(t, o); _m[t].m2 = 0; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = 1 << 7 | tt << 2 | d; SB(_me[t].m6, 2, 4, bridgetype); _me[t].m7 = 0; - _me[t].m8 = 0; + _me[t].m8 = INVALID_ROADTYPE << 6; } /** @@ -146,18 +146,19 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, D * @param owner_tram the new owner of the tram on the bridge * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing - * @param rts the road types of the bridge + * @param road_rt the road type of the bridge + * @param tram_rt the tram type of the bridge * @param upgrade whether the bridge is an upgrade instead of a totally new bridge */ -static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadTypes rts, bool upgrade) +static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadType road_rt, RoadType tram_rt, bool upgrade) { // Backup custom bridgehead data. uint custom_bridge_head_backup = GB(_m[t].m2, 0, 8); MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD); - SetRoadOwner(t, ROADTYPE_ROAD, owner_road); - if (owner_tram != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, owner_tram); - SetRoadTypes(t, rts); + SetRoadOwner(t, RTT_ROAD, owner_road); + if (owner_tram != OWNER_TOWN) SetRoadOwner(t, RTT_TRAM, owner_tram); + SetRoadTypes(t, road_rt, tram_rt); // Restore custom bridgehead data if we're upgrading an existing bridge. if (upgrade) SB(_m[t].m2, 0, 8, custom_bridge_head_backup); @@ -182,6 +183,7 @@ static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetyp auto m8_backup = _me[t].m8; MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL); + _m[t].m4 = 0; _me[t].m8 = rt; if (upgrade) { @@ -234,15 +236,15 @@ static inline bool IsRoadCustomBridgeHeadTile(TileIndex t) /** * Returns the road bits for a (possibly custom) road bridge head * @param t The tile to analyze - * @param rt Road type. + * @param rtt Road/tram type. * @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD * @return road bits for the bridge head */ -static inline RoadBits GetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt) +static inline RoadBits GetCustomBridgeHeadRoadBits(TileIndex t, RoadTramType rtt) { assert_tile(IsBridgeTile(t), t); - if (!HasTileRoadType(t, rt)) return (RoadBits) 0; - RoadBits bits = (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X) ^ (RoadBits) GB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4); + if (!HasTileRoadType(t, rtt)) return (RoadBits) 0; + RoadBits bits = (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X) ^ (RoadBits) GB(_m[t].m2, rtt == RTT_TRAM ? 4 : 0, 4); return bits; } @@ -254,26 +256,26 @@ static inline RoadBits GetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt) */ static inline RoadBits GetCustomBridgeHeadAllRoadBits(TileIndex t) { - return GetCustomBridgeHeadRoadBits(t, ROADTYPE_ROAD) | GetCustomBridgeHeadRoadBits(t, ROADTYPE_TRAM); + return GetCustomBridgeHeadRoadBits(t, RTT_ROAD) | GetCustomBridgeHeadRoadBits(t, RTT_TRAM); } /** * Sets the road bits for a (possibly custom) road bridge head * @param t The tile to modify - * @param rt Road type. + * @param rtt Road/tram type. * @param bits The road bits. * @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD * @pre HasTileRoadType() must be set correctly before calling this */ -static inline void SetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt, RoadBits bits) +static inline void SetCustomBridgeHeadRoadBits(TileIndex t, RoadTramType rtt, RoadBits bits) { assert_tile(IsBridgeTile(t), t); - if (HasTileRoadType(t, rt)) { + if (HasTileRoadType(t, rtt)) { assert(bits != ROAD_NONE); - SB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4, bits ^ (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X)); + SB(_m[t].m2, rtt == RTT_TRAM ? 4 : 0, 4, bits ^ (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X)); } else { assert(bits == ROAD_NONE); - SB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4, 0); + SB(_m[t].m2, rtt == RTT_TRAM ? 4 : 0, 4, 0); } } diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 4d3b920909..3781f2d0ac 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1015,8 +1015,8 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte struct BuildVehicleWindow : Window { VehicleType vehicle_type; ///< Type of vehicles shown in the window. union { - RailType railtype; ///< Rail type to show, or #RAILTYPE_END. - RoadTypes roadtypes; ///< Road type to show, or #ROADTYPES_ALL. + RailType railtype; ///< Rail type to show, or #INVALID_RAILTYPE. + RoadType roadtype; ///< Road type to show, or #INVALID_ROADTYPE. } filter; ///< Filter to apply. bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction byte sort_criteria; ///< Current sort criterium. @@ -1062,6 +1062,7 @@ struct BuildVehicleWindow : Window { this->virtual_train_out = virtual_train_out; this->virtual_train_mode = (virtual_train_out != nullptr); if (this->virtual_train_mode) this->window_number = 0; + this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; this->sel_engine = INVALID_ENGINE; @@ -1069,19 +1070,7 @@ struct BuildVehicleWindow : Window { this->descending_sort_order = _engine_sort_last_order[type]; this->show_hidden_engines = _engine_sort_show_hidden_engines[type]; - switch (type) { - default: NOT_REACHED(); - case VEH_TRAIN: - this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); - break; - case VEH_ROAD: - this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile); - case VEH_SHIP: - case VEH_AIRCRAFT: - break; - } - - this->listview_mode = !(this->virtual_train_mode) && (this->window_number <= VEH_END); + this->UpdateFilterByTile(); this->CreateNestedTree(); @@ -1127,6 +1116,36 @@ struct BuildVehicleWindow : Window { } } + /** Set the filter type according to the depot type */ + void UpdateFilterByTile() + { + switch (this->vehicle_type) { + default: NOT_REACHED(); + case VEH_TRAIN: + if (this->listview_mode || this->virtual_train_mode) { + this->filter.railtype = INVALID_RAILTYPE; + } else { + this->filter.railtype = GetRailType(this->window_number); + } + break; + + case VEH_ROAD: + if (this->listview_mode || this->virtual_train_mode) { + this->filter.roadtype = INVALID_ROADTYPE; + } else { + this->filter.roadtype = GetRoadTypeRoad(this->window_number); + if (this->filter.roadtype == INVALID_ROADTYPE) { + this->filter.roadtype = GetRoadTypeTram(this->window_number); + } + } + break; + + case VEH_SHIP: + case VEH_AIRCRAFT: + break; + } + } + /** Populate the filter list and set the cargo filter criteria. */ void SetCargoFilterArray() { @@ -1236,8 +1255,6 @@ struct BuildVehicleWindow : Window { int num_engines = 0; int num_wagons = 0; - this->filter.railtype = (this->listview_mode || this->virtual_train_mode) ? RAILTYPE_END : GetRailType(this->window_number); - this->eng_list.clear(); /* Make list of all available train engines and wagons. @@ -1250,7 +1267,7 @@ struct BuildVehicleWindow : Window { EngineID eid = e->index; const RailVehicleInfo *rvi = &e->u.rail; - if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; + if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; /* Filter now! So num_engines and num_wagons is valid */ @@ -1293,7 +1310,8 @@ struct BuildVehicleWindow : Window { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; - if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue; + if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue; + this->eng_list.push_back(eid); if (eid == this->sel_engine) sel_id = eid; @@ -1351,6 +1369,10 @@ struct BuildVehicleWindow : Window { void GenerateBuildList() { if (!this->eng_list.NeedRebuild()) return; + + /* Update filter type in case the road/railtype of the depot got converted */ + this->UpdateFilterByTile(); + switch (this->vehicle_type) { default: NOT_REACHED(); case VEH_TRAIN: @@ -1482,6 +1504,9 @@ struct BuildVehicleWindow : Window { if (this->vehicle_type == VEH_TRAIN && !this->listview_mode && !this->virtual_train_mode) { const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); SetDParam(0, rti->strings.build_caption); + } else if (this->vehicle_type == VEH_ROAD && !this->listview_mode) { + const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype); + SetDParam(0, rti->strings.build_caption); } else { SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); } diff --git a/src/command.cpp b/src/command.cpp index ff95d3777b..f768dee597 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -75,6 +75,8 @@ CommandProc CmdBuildRoad; CommandProc CmdBuildRoadDepot; +CommandProc CmdConvertRoad; + CommandProc CmdBuildAirport; CommandProc CmdBuildDock; @@ -298,6 +300,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdRemoveLongRoad, CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed. DEF_CMD(CmdBuildRoad, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD DEF_CMD(CmdBuildRoadDepot, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_DEPOT + DEF_CMD(CmdConvertRoad, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_ROAD DEF_CMD(CmdBuildAirport, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_AIRPORT DEF_CMD(CmdBuildDock, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_DOCK diff --git a/src/command_type.h b/src/command_type.h index 6c4b0036aa..ff4104f3f4 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -242,6 +242,7 @@ enum Commands { CMD_REMOVE_LONG_ROAD, ///< remove a complete road (not a "half" one) CMD_BUILD_ROAD, ///< build a "half" road CMD_BUILD_ROAD_DEPOT, ///< build a road depot + CMD_CONVERT_ROAD, ///< convert a road type CMD_BUILD_AIRPORT, ///< build an airport diff --git a/src/company_base.h b/src/company_base.h index 584c65b4ba..f8cca24c01 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -44,6 +44,9 @@ struct CompanyInfrastructure { return total; } + uint32 GetRoadTotal() const; + uint32 GetTramTotal() const; + char *Dump(char *buffer, const char *last) const; }; diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index c63e43457d..cd2f08761f 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -568,7 +568,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER; c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); c->inaugurated_year = _cur_year; RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face @@ -1183,11 +1183,40 @@ int CompanyServiceInterval(const Company *c, VehicleType type) } } +/** + * Get total sum of all owned road bits. + * @return Combined total road road bits. + */ +uint32 CompanyInfrastructure::GetRoadTotal() const +{ + uint32 total = 0; + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsRoad(rt)) total += this->road[rt]; + } + return total; +} + +/** + * Get total sum of all owned tram bits. + * @return Combined total of tram road bits. + */ +uint32 CompanyInfrastructure::GetTramTotal() const +{ + uint32 total = 0; + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsTram(rt)) total += this->road[rt]; + } + return total; +} + char *CompanyInfrastructure::Dump(char *buffer, const char *last) const { for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { if (rail[rt]) buffer += seprintf(buffer, last, "Rail: %s: %u\n", GetStringPtr(GetRailTypeInfo(rt)->strings.name), rail[rt]); } + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (road[rt]) buffer += seprintf(buffer, last, "%s: %s: %u\n", RoadTypeIsTram(rt) ? "Tram" : "Road", GetStringPtr(GetRoadTypeInfo(rt)->strings.name), road[rt]); + } buffer += seprintf(buffer, last, "Signal: %u\n", signal); buffer += seprintf(buffer, last, "Road: %u\n", road[ROADTYPE_ROAD]); buffer += seprintf(buffer, last, "Tram: %u\n", road[ROADTYPE_TRAM]); diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 9b59158c0f..4491cfafc5 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -31,6 +31,7 @@ #include "core/geometry_func.hpp" #include "object_type.h" #include "rail.h" +#include "road.h" #include "engine_base.h" #include "window_func.h" #include "road_func.h" @@ -1786,6 +1787,10 @@ static const NWidgetPart _nested_company_infrastructure_widgets[] = { NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), + EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), @@ -1823,7 +1828,7 @@ struct CompanyInfrastructureWindow : Window void UpdateRailRoadTypes() { this->railtypes = RAILTYPES_NONE; - this->roadtypes = ROADTYPES_ROAD; // Road is always available. + this->roadtypes = ROADTYPES_NONE; /* Find the used railtypes. */ Engine *e; @@ -1836,14 +1841,16 @@ struct CompanyInfrastructureWindow : Window /* Get the date introduced railtypes as well. */ this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY); - /* Tram is only visible when there will be a tram. */ + /* Find the used roadtypes. */ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue; - this->roadtypes |= ROADTYPES_TRAM; - break; + this->roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes; } + + /* Get the date introduced roadtypes as well. */ + this->roadtypes = AddDateIntroducedRoadTypes(this->roadtypes, MAX_DAY); + this->roadtypes &= ~_roadtypes_hidden_mask; } /** Get total infrastructure maintenance cost. */ @@ -1858,8 +1865,11 @@ struct CompanyInfrastructureWindow : Window } total += SignalMaintenanceCost(c->infrastructure.signal); - if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]); - if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (HasBit(this->roadtypes, rt)) total += RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total); + } total += CanalMaintenanceCost(c->infrastructure.water); total += StationMaintenanceCost(c->infrastructure.station); @@ -1887,7 +1897,8 @@ struct CompanyInfrastructureWindow : Window size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width); - for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { if (HasBit(this->railtypes, rt)) { lines++; SetDParam(0, GetRailTypeInfo(rt)->strings.name); @@ -1903,18 +1914,19 @@ struct CompanyInfrastructureWindow : Window break; } - case WID_CI_ROAD_DESC: { - uint lines = 1; + case WID_CI_ROAD_DESC: + case WID_CI_TRAM_DESC: { + uint lines = 0; - size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width); + size->width = max(size->width, GetStringBoundingBox(widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT).width); - if (HasBit(this->roadtypes, ROADTYPE_ROAD)) { - lines++; - size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT); - } - if (HasBit(this->roadtypes, ROADTYPE_TRAM)) { - lines++; - size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT); + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { + lines++; + SetDParam(0, GetRoadTypeInfo(rt)->strings.name); + size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT); + } } size->height = max(size->height, lines * FONT_HEIGHT_NORMAL); @@ -1934,6 +1946,7 @@ struct CompanyInfrastructureWindow : Window case WID_CI_RAIL_COUNT: case WID_CI_ROAD_COUNT: + case WID_CI_TRAM_COUNT: case WID_CI_WATER_COUNT: case WID_CI_STATION_COUNT: case WID_CI_TOTAL: { @@ -1947,9 +1960,12 @@ struct CompanyInfrastructureWindow : Window } max_val = max(max_val, c->infrastructure.signal); max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal)); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { max_val = max(max_val, c->infrastructure.road[rt]); - max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt])); + max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total)); + } max_val = max(max_val, c->infrastructure.water); max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water)); @@ -2045,26 +2061,32 @@ struct CompanyInfrastructureWindow : Window } case WID_CI_ROAD_DESC: - DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT); - - if (this->roadtypes != ROADTYPES_NONE) { - if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD); - if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY); - } else { - /* No valid roadtypes. */ - DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + case WID_CI_TRAM_DESC: { + DrawString(r.left, r.right, y, widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT); + + /* Draw name of each valid roadtype. */ + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { + SetDParam(0, GetRoadTypeInfo(rt)->strings.name); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); + } } break; + } case WID_CI_ROAD_COUNT: - if (HasBit(this->roadtypes, ROADTYPE_ROAD)) { - this->DrawCountLine(r, y, c->infrastructure.road[ROADTYPE_ROAD], RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD])); - } - if (HasBit(this->roadtypes, ROADTYPE_TRAM)) { - this->DrawCountLine(r, y, c->infrastructure.road[ROADTYPE_TRAM], RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM])); + case WID_CI_TRAM_COUNT: { + uint32 road_tram_total = widget == WID_CI_ROAD_COUNT ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal(); + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_COUNT)) { + this->DrawCountLine(r, y, c->infrastructure.road[rt], RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_tram_total)); + } } break; + } case WID_CI_WATER_DESC: DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT); diff --git a/src/economy.cpp b/src/economy.cpp index e3d0fd1a60..5635578003 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -729,8 +729,10 @@ static void CompaniesGenStatistics() if (c->infrastructure.rail[rt] != 0) cost.AddCost(RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); } cost.AddCost(SignalMaintenanceCost(c->infrastructure.signal)); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { - if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt])); + if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total)); } cost.AddCost(CanalMaintenanceCost(c->infrastructure.water)); cost.AddCost(StationMaintenanceCost(c->infrastructure.station)); diff --git a/src/engine.cpp b/src/engine.cpp index 8e9eeb6242..11a17aea11 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -718,7 +718,7 @@ void StartupEngines() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); } /* Invalidate any open purchase lists */ @@ -740,7 +740,8 @@ static void AcceptEnginePreview(EngineID eid, CompanyID company) assert(e->u.rail.railtype < RAILTYPE_END); c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { - SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + assert(e->u.road.roadtype < ROADTYPE_END); + c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date); } e->preview_company = INVALID_COMPANY; @@ -820,6 +821,7 @@ void EnginesDailyLoop() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date); + c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, _date); } if (_cur_year >= _year_engine_aging_stops) return; @@ -961,7 +963,8 @@ static void NewVehicleAvailable(Engine *e) FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { /* maybe make another road type available */ - FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + assert(e->u.road.roadtype < ROADTYPE_END); + FOR_ALL_COMPANIES(c) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date); } /* Only broadcast event if AIs are able to build this vehicle type. */ @@ -1108,6 +1111,11 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company) const Company *c = Company::Get(company); if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false; } + if (type == VEH_ROAD && company != OWNER_DEITY) { + /* Check if the road type is available to this company */ + const Company *c = Company::Get(company); + if ((GetRoadTypeInfo(e->u.road.roadtype)->powered_roadtypes & c->avail_roadtypes) == ROADTYPES_NONE) return false; + } return true; } diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp index 2ecad90115..79cbe01706 100644 --- a/src/engine_gui.cpp +++ b/src/engine_gui.cpp @@ -19,6 +19,7 @@ #include "vehicle_func.h" #include "company_func.h" #include "rail.h" +#include "road.h" #include "settings_type.h" #include "train.h" #include "roadveh.h" @@ -41,7 +42,8 @@ StringID GetEngineCategoryName(EngineID engine) const Engine *e = Engine::Get(engine); switch (e->type) { default: NOT_REACHED(); - case VEH_ROAD: return STR_ENGINE_PREVIEW_ROAD_VEHICLE; + case VEH_ROAD: + return GetRoadTypeInfo(e->u.road.roadtype)->strings.new_engine; case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT; case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP; case VEH_TRAIN: diff --git a/src/engine_type.h b/src/engine_type.h index 1cc0452a5f..6cc8dc68eb 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -14,6 +14,7 @@ #include "economy_type.h" #include "rail_type.h" +#include "road_type.h" #include "cargo_type.h" #include "date_type.h" #include "sound_type.h" @@ -123,6 +124,7 @@ struct RoadVehicleInfo { uint8 air_drag; ///< Coefficient of air drag byte visual_effect; ///< Bitstuffed NewGRF visual effect data byte shorten_factor; ///< length on main map for this type is 8 - shorten_factor + RoadType roadtype; ///< Road type }; /** diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp index 26a61a7903..be093ca00c 100644 --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -64,6 +64,7 @@ #include "../script/api/game/game_rail.hpp.sq" #include "../script/api/game/game_railtypelist.hpp.sq" #include "../script/api/game/game_road.hpp.sq" +#include "../script/api/game/game_roadtypelist.hpp.sq" #include "../script/api/game/game_sign.hpp.sq" #include "../script/api/game/game_signlist.hpp.sq" #include "../script/api/game/game_station.hpp.sq" @@ -174,6 +175,7 @@ void GameInstance::RegisterAPI() SQGSRail_Register(this->engine); SQGSRailTypeList_Register(this->engine); SQGSRoad_Register(this->engine); + SQGSRoadTypeList_Register(this->engine); SQGSSign_Register(this->engine); SQGSSignList_Register(this->engine); SQGSStation_Register(this->engine); diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 8534c842d9..b707974c4e 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -30,7 +30,7 @@ void GroundVehicle::PowerChanged() uint32 total_power = 0; uint32 max_te = 0; uint32 number_of_parts = 0; - uint16 max_track_speed = v->GetDisplayMaxSpeed(); + uint16 max_track_speed = this->vcache.cached_max_speed; // Max track speed in internal units. this->CalculatePower(total_power, max_te, false); diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index f983cb0e8d..069a3a06e4 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -37,7 +37,7 @@ struct GroundVehicleCache { uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle (valid only for the first engine). /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */ - uint16 cached_max_track_speed; ///< Maximum consist speed limited by track type (valid only for the first engine). + uint16 cached_max_track_speed; ///< Maximum consist speed (in internal units) limited by track type (valid only for the first engine). uint32 cached_power; ///< Total power of the consist (valid only for the first engine). uint32 cached_air_drag; ///< Air drag coefficient of the vehicle (valid only for the first engine). diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index af991b7eec..57379d3bc3 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -3255,8 +3255,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spoorstukke: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seine STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Padstukke: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Pad -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tremweg STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Waterteëls: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanale STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasies: @@ -4268,7 +4266,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Moet eer STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Geen geskikte treinspoor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Moet eers spoor verwyder STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Pad is een rigting of geblok -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Vlak kruisings word nie toegelaat vir die spoor tipe nie +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Vlak kruisings word nie toegelaat vir die spoor tipe nie STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan nie seinligte hier bou nie... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan nie spore hier bou nie... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan nie spore hier verwyder nie... diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index f785695c34..ecce7f65c5 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -3733,7 +3733,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}يجب STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}... مسار السكة الحديدية غير مناسب STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}يجب إزاله السكه الحديديه اولاً STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}الطريق باتجاه واحد او ربما يكون مسدوداً -STR_ERROR_CROSSING_DISALLOWED :{WHITE}التقاطع المتعدد غير متاح لهذا النوع من السكك +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}التقاطع المتعدد غير متاح لهذا النوع من السكك STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}تعذر بناء اﻹشارات هنا... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}تعذر بناء السكه الحديديه هنا... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}تعذر إزاله السكه الحديديه من هنا... diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 535fb6a91a..40f1048cdd 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -3143,8 +3143,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Trenbide sailak: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seinaleak STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Errepide sailak: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Errepidea -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tranbia sailak STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Urbide sailak: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalak STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Geltokiak: @@ -4140,7 +4138,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Lehendab STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ez dago trenbide egokirik STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Lehendabizi trenbidea ezabatu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Errepidea norabide bakarrekoa da edo blokeatua dago -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ezin dira maila bereko pasaguneak egin trenbide mota honetan +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ezin dira maila bereko pasaguneak egin trenbide mota honetan STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ezin da seinalerik hemen eraiki... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ezin da trenbiderik hemen eraiki... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ezin da hemengo trenbidea ezabatu... diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 94d5cb7763..2d0adba740 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -3604,8 +3604,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Iнфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Чыгуначныя элемэнты: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Сыґналы STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Дарожныя элемэнты: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Дарогi -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамваi STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Водныя клеткi: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Каналы STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станцыi: @@ -4653,7 +4651,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Спач STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Няма прыдатных рэйкаў STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Спачатку выдаліце чыгунку STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Дарога аднабаковая або блякаваная -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Праз гэты від рэйкаў забаронена будаваць пераезды +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Праз гэты від рэйкаў забаронена будаваць пераезды STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Тут немагчыма паставіць сьветлафор... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Тут немагчыма пракласьцi рэйкі... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Не атрымалася выдаліць чыгунку... diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 6177cca56c..65e1bce25a 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -3314,8 +3314,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Partes de ferrovias: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinais STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Partes de rodovias: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Rodovia -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Linha de bonde STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Partes d'água: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canais STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estações: @@ -4343,7 +4341,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Remova o STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tipo de linha não apropriado STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Remova a ferrovia antes STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Rua é mão única ou está bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Cruzamentos de nível não são permitidos para esse tipo de trilho +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Cruzamentos de nível não são permitidos para esse tipo de trilho STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Impossível construir sinais aqui... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Impossível construir ferrovia aqui... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Impossível remover a ferrovia daqui... diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index d218d75aeb..c5cd135cd9 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -3184,8 +3184,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Инфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Релсови части: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Сигнали STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Пътни части: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Път -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамвай STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Водни части: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Канали STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станции: @@ -4197,7 +4195,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Първ STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Неподходящ за употреба релсов път STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Първо трябва да бъде премахнат релсовия път STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Пътят е еднопосочен или блокиран -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Пресичането на различни видове ЖП линии не е позволено. +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Пресичането на различни видове ЖП линии не е позволено. STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Тук не може да бъдат поставени сигнали... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Тук не могат да бъдат построени ЖП релси... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Не може да премахнеш тези ЖП релси... diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index d44daaf95e..9c3c4ffee4 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -3353,8 +3353,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Trossos de vies: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Senyals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Trossos de carretera: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Carretera -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvia STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Cel·les d'aigua: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estacions: @@ -4388,7 +4386,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}...abans STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Via de tren no apropiada STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}...abans s'ha de treure la via. STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}La carretera és un d'un sol sentit o està bloquejada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Els passos a nivell no estan permesos en aquest tipus de via +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Els passos a nivell no estan permesos en aquest tipus de via STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Aquí no es poden construir senyals... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Aquí no es pot construir la via de tren... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Aquí no es pot treure la via de tren... diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 7a4739fa99..1c639c239e 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -3454,8 +3454,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Dijelovi pruge: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Dijelovi ceste: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajska pruga STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Polje s vodom: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Postaje: @@ -4501,7 +4499,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprije STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nije prikladno za želježnicku prugu STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprije je potrebno ukloniti željezničku prugu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je jednosmjerna ili je blokirana -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Pružni prijelazi nisu dopušteni za ovu vrstu pruge +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Pružni prijelazi nisu dopušteni za ovu vrstu pruge STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ovdje nije moguće postaviti signale... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ovdje nije moguće izgraditi željezničke tračnice... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nije moguće ukloniti željezničku prugu odavde... diff --git a/src/lang/czech.txt b/src/lang/czech.txt index fcb8c37cc4..943ac7f891 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -3374,8 +3374,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Železniční oblasti: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Semafory STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Silniční oblasti: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Silnice -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajové koleje STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vodní oblasti: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Průplavy STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: @@ -4406,7 +4404,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Je nutn STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Žádné použitelné koleje STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Je nutné nejprve odstranit koleje STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Silnice je jednosměrná nebo zablokovaná -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Železniční přejezd není povolen pro tento typ kolejí +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Železniční přejezd není povolen pro tento typ kolejí STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Zde nelze postavit semafory... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Zde nelze postavit koleje... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Odsud nelze odstranit koleje... diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 7294291d4b..638cbd1971 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -3356,8 +3356,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spor-stykker: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vej-stykker: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vej -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Sporvogne STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vand-felter: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanaler STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationer: @@ -4391,7 +4389,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Det er n STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ingen brugbar jernbane STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Det er nødvendigt at fjerne jernbaneskinnerne først STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vejen er ensrettet eller blokeret -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Niveaukrydsning ikke tilladt for denne type skinner +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Niveaukrydsning ikke tilladt for denne type skinner STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan ikke bygge signaler her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan ikke bygge jernbane her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan ikke fjerne jernbane herfra... diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 4ec2afc301..ded83968ea 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -3358,8 +3358,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spoordelen: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seinen STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Wegdelen: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Weg -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramsporen STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Watertegels: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalen STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -4405,7 +4403,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Verwijde STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Geen bruikbaar spoor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Moet spoor eerst verwijderen STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Weg is eenrichtingsverkeer of geblokkeerd -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Gelijkvloerse kruisingen zijn niet toegestaan voor dit type spoor +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Gelijkvloerse kruisingen zijn niet toegestaan voor dit type spoor STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan hier geen seinen plaatsen... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan hier geen spoor leggen... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan hier geen spoor verwijderen... diff --git a/src/lang/english.txt b/src/lang/english.txt index 1955ce42c0..41ba688cd7 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -344,6 +344,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Build tramways STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. @@ -364,6 +365,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscap STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Tramway construction STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate @@ -2930,6 +2932,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build ro STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Convert/Upgrade the type of road. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Convert/Upgrade the type of tram. Shift toggles building/showing cost estimate + +STR_ROAD_NAME_ROAD :Road +STR_ROAD_NAME_TRAM :Tramway # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation @@ -3147,8 +3154,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Rail type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Road type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tram type: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tram speed limit: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks @@ -4016,8 +4026,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Tram pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -4165,10 +4174,15 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Ra STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :New Tram Vehicles + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :New Road Vehicles STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Weight: {GOLD}{WEIGHT_SHORT} @@ -4334,12 +4348,17 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :electrified railway locomotive +STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive +STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive + STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle +STR_ENGINE_PREVIEW_TRAM_VEHICLE :tramway vehicle + STR_ENGINE_PREVIEW_AIRCRAFT :aircraft STR_ENGINE_PREVIEW_SHIP :ship -STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive -STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} @@ -4378,14 +4397,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch b STR_REPLACE_ENGINES :Engines STR_REPLACE_WAGONS :Wagons STR_REPLACE_ALL_RAILTYPE :All rail vehicles +STR_REPLACE_ALL_ROADTYPE :All road vehicles STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for +STR_REPLACE_HELP_ROADTYPE :{BLACK}Choose the road type you want to replace engines for STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any STR_REPLACE_RAIL_VEHICLES :Rail Vehicles STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles +STR_REPLACE_ROAD_VEHICLES :Road Vehicles +STR_REPLACE_TRAM_VEHICLES :Tramway Vehicles + STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer @@ -5290,7 +5314,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Level crossings not allowed for this road type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... @@ -5312,6 +5337,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't re STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no tramway +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Can't convert road type here... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Can't convert tram type here... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}No suitable road +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}No suitable tramway +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... incompatible road +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... incompatible tramway # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index e66c26d545..feeb4a6a29 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -3221,8 +3221,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -4217,7 +4215,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Level crossings not allowed for this rail type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 2e575e29c7..c1d0b2438c 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -3355,8 +3355,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Streetcar STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -4402,7 +4400,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railroad track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railroad track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Grade crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Grade crossings not allowed for this rail type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railroad track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railroad track from here... diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index 9266a2c593..6eb35a8272 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -3645,7 +3645,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Unue vi STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nekonvena fervojtrako STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Antaŭe devas la trako esti detruita STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Strato estas unudirekta aŭ blokita -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Traknivelaj pasejoj ne permesa por ĉi tio fervojtipo +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Traknivelaj pasejoj ne permesa por ĉi tio fervojtipo STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ne povas konstrui signalojn ĉi tie... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ne povas konstrui trakon ĉi tie... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ne povas forigi trakon de ĉi tie... diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index ef083fd932..defd29ecc8 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -3332,8 +3332,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE} {COMPAN STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Raudtee tükid: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaalid STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Tee tükid: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Tee -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Trammitee STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Veekogu ruudud: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalid STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Jaamad: @@ -4351,7 +4349,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Signaali STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Sobiv rongitee puudub STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rööbastee tuleb eelnevalt lammutada STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Läbipääsmatu või ühesuunaline maantee -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ülesõidukohad on selle raudteetüübi puhul keelatud +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ülesõidukohad on selle raudteetüübi puhul keelatud STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Siia ei saa signaale rajada... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Siia ei saa raudteed ehitada... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Siit ei saa raudteed lammutada... diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 453c43aec5..e76aa218ff 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -2889,8 +2889,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Innanker STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Jarnbreyta pettir: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Tekin STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vega pettir: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vegur -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Sporvognur STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vatn puntar: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Siglingarennir STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Støðir: @@ -3790,7 +3788,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Neyðugt STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ikki hóskandi jarnbreyt STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Neyðugt at beina burtur jarnbreyt fyrst STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vegur er einvegis ella blokeraður -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Javnir krossvegir ikki loyvdir fyri hetta slagi av tok bana +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Javnir krossvegir ikki loyvdir fyri hetta slagi av tok bana STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kann ikki byggja jarnbreytatekin her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kann ikki byggja jarnbreyt her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kann ikki beina burtur jarnbreyt hagani... diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 17a3fc283c..68d53fd7d9 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -3358,8 +3358,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rautatiepalat: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Opastimet STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Teiden palat: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Tie -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Raitiotie STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vesiruudut: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanavat STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Asemat: @@ -4405,7 +4403,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Opastime STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ei kelvollista rautatietä. STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rautatie pitää poistaa ensin. STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Tie on yksisuuntainen tai suljettu -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Tasoristeykset eivät ole sallittu tälle raidetyypille +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Tasoristeykset eivät ole sallittu tälle raidetyypille STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Opastinta ei voi rakentaa. STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Rautatietä ei voi rakentaa. STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Rautatietä ei voi poistaa. diff --git a/src/lang/french.txt b/src/lang/french.txt index 4fb27aea34..0357f31425 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -3356,8 +3356,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Morceaux de voie ferrée{NBSP}: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaux STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Morceaux de route{NBSP}: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Route -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Cases d'eau{NBSP}: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canaux STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations{NBSP}: @@ -4403,7 +4401,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Vous dev STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Aucuns rails convenables STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Vous devez d'abord enlever les rails STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}La route est à sens unique ou bloquée -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Les passages à niveau ne sont pas authorisés pour ce type de rails +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Les passages à niveau ne sont pas authorisés pour ce type de rails STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Impossible de construire des signaux ici... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Impossible de construire des rails ici... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Impossible de retirer les rails d'ici... diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index e1dc125827..d9ad5ad2a7 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -3533,8 +3533,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Am bun-s STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Earrannan rèile: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Comharran STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Earrannan rathaid: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Rathad -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Slighe-trama STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Leacan uisge: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canalan STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stèiseanan: @@ -4563,7 +4561,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Feumaidh STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Chan eil slighe rèile iomchaidh ann STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Feumaidh tu an t-slighe rèile a thoirt air falbh an toiseach STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Rathad aon-shligheach no bacte -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Chan eil staranan-rèile ceadaichte leis an t-seòrsa dhe rèile seo +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Chan eil staranan-rèile ceadaichte leis an t-seòrsa dhe rèile seo STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Cha ghabh comharran togail an-seo... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Cha ghabh slighe-rèile togail an-seo... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Cha ghabh an t-slighe-rèile toirt air falbh an-seo... diff --git a/src/lang/galician.txt b/src/lang/galician.txt index ee24364467..af98027736 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -3259,8 +3259,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Segmentos de vía de ferrocarril: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinais STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Segmentos de estrada: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Estrada -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE} Tranvía STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Cadros de auga: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canles STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estacións: @@ -4287,7 +4285,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Debes re STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Non hay vía de ferrocarril adecuada STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Debes elimina-la vía de ferrocarril primeiro STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}A estrada é de sentido único ou está bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Non se permiten pasos a nivel con este tipo de carril +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Non se permiten pasos a nivel con este tipo de carril STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Non se poden construír sinais aquí... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Non se pode construír vía ferroviaria aquí... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Non se pode elimina-la vía ferroviaria de aquí... diff --git a/src/lang/german.txt b/src/lang/german.txt index a2720eb0ef..68377881f2 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -3884,8 +3884,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Schienenfelder: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signale STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Straßenfelder: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Straße -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Straßenbahnfelder STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Wasserfelder: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanäle STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationen: @@ -5075,7 +5073,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Signal m STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Keine geeigneten Gleise STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Gleise müssen erst abgerissen werden STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Einbahnstraße oder blockierter Weg -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Bahnübergänge sind für diesen Schienentyp nicht erlaubt +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Bahnübergänge sind für diesen Schienentyp nicht erlaubt STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Signal kann hier nicht aufgestellt werden... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Gleise können hier nicht verlegt werden... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Gleise können nicht abgerissen werden... diff --git a/src/lang/greek.txt b/src/lang/greek.txt index e218864515..914ac71e97 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -3462,8 +3462,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Υποδ STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Κομμάτια σιδηροτροχιάς: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Σήματα STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Κομμάτια δρόμου: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Δρόμος -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Τροχιόδρομος STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Τετραγωνίδια νερού: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Κανάλια STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Σταθμοί: @@ -4514,7 +4512,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Πρέπ STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Μη συμβατή σιδηροτροχιά STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Πρέπει να αφαιρεθεί ο σιδηρόδρομος πρώτα STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Η δρόμος είναι μονόδρομος ή μπλοκαρισμένος -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Δεν επιτρέπονται ισόπεδες διασταυρώσεις για αυτόν τον τύπο σιδηροδρόμου +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Δεν επιτρέπονται ισόπεδες διασταυρώσεις για αυτόν τον τύπο σιδηροδρόμου STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Δεν μπορούν να τοποθετοηθούν σηματοδότες εδώ... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Δεν μπορεί να κτιστεί σιδηρόδρομος εδώ... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Δεν μπορεί να αφαιρεθεί σιδηρόδρομος από εδώ... diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index 70a789be08..24929a4788 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -3312,8 +3312,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}תתיו STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}חלקי מסילה: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}רמזורים STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}חלקי כביש: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}כביש -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}מסילת רכבת קלה STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}משבצות מים: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}תעלות STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}תחנות: @@ -4342,7 +4340,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}יש ל STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}אין מסילת רכבת מתאימה STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}יש להסיר את המסילה הקיימת תחילה STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}כביש חד סיטרי או חסום -STR_ERROR_CROSSING_DISALLOWED :{WHITE}מפגשי כביש/מסילה אין אפשריים עבור סוג מסילה זה +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}מפגשי כביש/מסילה אין אפשריים עבור סוג מסילה זה STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}לא ניתן למקם רמזורים כאן... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}לא ניתן להניח פסי רכבת כאן... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}לא ניתן להסיר פסי רכבת ממשבצת זו... diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 8b2fe786f7..c8e3895765 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -3419,8 +3419,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Vasúti elemek: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Vasúti jelzők STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Közúti elemek: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Út -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Villamospálya STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vízi elemek: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Csatornák STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Állomások: @@ -4466,7 +4464,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Előszö STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nincs megfelelő vasúti pálya STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Előbb le kell rombolnod a vasúti pályát STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}... az út egyirányú vagy blokkolt -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ehhez a síntipushoz nem megengedett vasúti átjárók építése +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ehhez a síntipushoz nem megengedett vasúti átjárók építése STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nem helyezhetsz ide jelzőt... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nem építhetsz ide vasúti pályát... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nem szedheted fel innen a vasúti pályát... diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 0d74d532aa..b7d2c906de 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -3045,8 +3045,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Innviði STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Járnbrautarspor: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Umferðarmerki STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vegir: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vegir -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Sporvagnaspor STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vatns reitir: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Skipaskurðir STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stöðvar: @@ -4030,7 +4028,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Verður STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ekkert hentugt járnbrautarspor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Verður að fjarlægja járnbrautarspor fyrst STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vegurinn er einstefnuvegur eða stíflaður -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Gatnamót ekki leyfð fyrir þessa tegund járnbrautarspora +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Gatnamót ekki leyfð fyrir þessa tegund járnbrautarspora STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Get ekki byggt umferðarmerki hér... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Get ekki byggt járnbrautarspor hér... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Get ekki fjarlægt járnbrautarspor héðan... diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index 8b223f3a7b..65c76d2069 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -3301,8 +3301,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Bagian rel: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinyal STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Bagian jalan: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Jalan raya -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Rel Trem STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Perairan: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanal STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasiun: @@ -4333,7 +4331,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Sinyal h STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tidak tersedia rel yang sesuai STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Harus membongkar rel terlebih dahulu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Jalannya satu arah atau terhalang -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Perlintasan tingkat tidak diperbolehkan pada tipe rel ini +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Perlintasan tingkat tidak diperbolehkan pada tipe rel ini STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Tidak dapat membangun sinyal disini STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Tidak dapat membangun jalur rel disini STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Tidak dapat menghapus jalur rel dari sini diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 6d43958ccb..5ce6f63522 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -3254,8 +3254,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Bonneaga STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Píosaí iarnróid: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Comharthaí STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Píosaí bóthair: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Bóthar -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Trambhealach STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Tíleanna uisce: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canálacha STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stáisiúin: @@ -4267,7 +4265,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Ní mór STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Níl ráillí iarnróid feiliúnacha ann STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Ní mór na ráillí iarnróid a bhaint ar dtús STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Is bóthar aonbhealaigh nó blocáilte é -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ní cheadaítear crosairí comhréidh don chineál ráille seo +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ní cheadaítear crosairí comhréidh don chineál ráille seo STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ní féidir comharthaí a thógáil anseo... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ní féidir ráillí iarnróid a thógáil anseo... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ní féidir ráillí iarnróid a bhaint as seo... diff --git a/src/lang/italian.txt b/src/lang/italian.txt index 9bac6561a5..e646e519e9 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -3388,8 +3388,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Segmenti ferroviari: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Segnali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Segmenti stradali: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Strada -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tranvia STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Riquadri d'acqua: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stazioni: @@ -4435,7 +4433,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Bisogna STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tipo di binari non adatti STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Bisogna rimuovere i binari prima STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}La strada è bloccata o a senso unico -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Passaggi a livello non consentiti per questo tipo di rotaia +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Passaggi a livello non consentiti per questo tipo di rotaia STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Impossibile costruire i segnali qui... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Impossibile costruire i binari qui... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Impossibile rimuovere i binari da qui... diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 11e204332b..73f784005f 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -3319,8 +3319,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}線路長: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}信号 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}道路長(含軌道): -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}道路 -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}軌道 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}水運長: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}運河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}停留施設数: @@ -4334,7 +4332,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}先に STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}適当な線路がありません STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}先に線路を撤去しなければなりません STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}道路は一方通行または進入禁止です -STR_ERROR_CROSSING_DISALLOWED :{WHITE}このレール種別との平面交差はできません +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}このレール種別との平面交差はできません STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}ここには信号を設置できません STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}ここには線路を建設できません STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}ここから線路を撤去できません diff --git a/src/lang/korean.txt b/src/lang/korean.txt index e807316baa..19697b7a22 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -4016,8 +4016,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}철도 기반시설: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}신호기 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}도로 기반시설: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}도로 -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}전찻길 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}해운 기반시설: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}운하 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}정거장 시설: @@ -5290,7 +5288,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}신호 STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}알맞지 않은 선로입니다. STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}선로를 먼저 제거하십시오. STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}도로가 일방통행이거나 막혔습니다 -STR_ERROR_CROSSING_DISALLOWED :{WHITE}이 철도 타입에서는 건널목을 만들 수 없습니다. +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}이 철도 타입에서는 건널목을 만들 수 없습니다. STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}여기에 신호기를 건설할 수 없습니다... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}여기에 선로를 건설할 수 없습니다... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}이 선로를 철거할 수 없습니다... diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 8ae8fd3a1b..f9fe0924d3 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -3514,8 +3514,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Partes ferriviariae: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalia STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Partes viariae: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Viariae -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Ferriviae stratariae STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Tegulae aquariae: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canales STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationes: @@ -4563,7 +4561,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Necesse STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nulla astaria idonea STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Necesse est ferriviam removere STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Via est monodromus vel obstructa -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Non licet huic typo ferriviae habere transitus +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Non licet huic typo ferriviae habere transitus STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Non licet signalia hic struere... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Non licet ferriviam hic struere... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Non licet ferriviam removere hic... diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index df7db4f961..42047bc4ad 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -3197,8 +3197,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Sliežu gabali: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signālierīces STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Ceļa gabali: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Ceļš -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajs STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Ūdens lauciņi: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanāli STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stacijas: @@ -4198,7 +4196,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Vispirms STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nav piemērota sliežu ceļa STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Vispirms ir jānoņem dzelzceļa sliedes STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Ceļs ir bloķēts vai vienvirziena -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Vienlīmeņa krustojumi šīm sliedēm nav atļauti +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Vienlīmeņa krustojumi šīm sliedēm nav atļauti STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Šeit nevar būvēt signālierīces... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Šeit nevar būvēt dzelzceļa posmu... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Šeit nevar nojaukt dzelzceļa posmu... diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index 262ac35792..248fe75232 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -3473,8 +3473,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Bėgių dalys: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalai STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Kelio dalys: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Kelias -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajus STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vandens langeliai: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalai STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stotys: @@ -4542,7 +4540,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Pirma re STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Netinkamas bėgis STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Pirmiau pašalinkite geležinkelio bėgius STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Kelias vienpusis ar užblokuotas -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Sankryžos tame pačiame aukštyje neleidžiamos šiam bėgių tipui +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Sankryžos tame pačiame aukštyje neleidžiamos šiam bėgių tipui STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Šviesoforo čia statyti negalima ... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Begių čia statyti negalima... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Šių bėgių pašalinti negalima... diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index 5c88d7f662..19810495c5 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -3334,8 +3334,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Schinnestécker: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Stroossestécker: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Strooss -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tram STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Waasserfelder: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanäl STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Statiounen: @@ -4377,7 +4375,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Signaler STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Keng gëeegent Schinnen STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}D'Schinne musse fir d'éischt ewech STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}D'Strooss ass eng Einbahn oder blockéiert -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Barrièren si fir dësen Schinnentyp net erlaabt +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Barrièren si fir dësen Schinnentyp net erlaabt STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kann d'Signaler hei net bauen... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kann d'Schinnen hei net bauen... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kann d'Schinnen hei net ewech huelen... diff --git a/src/lang/malay.txt b/src/lang/malay.txt index ff930b8bfe..68adfbc39e 100644 --- a/src/lang/malay.txt +++ b/src/lang/malay.txt @@ -2955,8 +2955,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Cebisan landasan: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Isyarat STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Cebisan jalanraya: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Jalanraya -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Laluan Trem STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Petak air: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Terusan STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stesen: @@ -3944,7 +3942,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Tanda-ta STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tiada landasan keretapi yang sesuai STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Landasan keretapi mesti dibuang terlebih dahulu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Jalanraya adalah sehala atau telah disekat -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Persimpangan bertingkat adalah tidak dibenarkan untuk jenis landasan ini +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Persimpangan bertingkat adalah tidak dibenarkan untuk jenis landasan ini STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Isyarat tidak dapat dibina di sini... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Landasan keretapi tidak dapat dibina di sini... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Landasan keretapi tidak dapat dibuang... diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 729de303e7..3d9df13003 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -3359,8 +3359,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Jernbanebiter: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Veibiter: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vei -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Trikkespor STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vannruter: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanaler STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasjoner: @@ -4407,7 +4405,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Må fjer STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ingen passende jernbanespor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Må fjerne jernbanespor først STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Veien er enveiskjørt eller blokkert -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Denne jernbanetypen tillater ikke planoverganger +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Denne jernbanetypen tillater ikke planoverganger STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan ikke bygge signaler her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan ikke bygge jernbanespor her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan ikke fjerne jernbanespor herfra... diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index 3afb9b9738..b692a7c97d 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -3173,8 +3173,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Togsporbitar: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signal STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vegstubbar: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Veg -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Trikkespor STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vannruter: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalar STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasjonar: @@ -4183,7 +4181,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Må fjer STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Upassande jernbanespor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Må fjerne jernbanespor først STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vegen er einvegskøyrd eller blokkert -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Overgang ikkje tillate for denne typen jernbane +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Overgang ikkje tillate for denne typen jernbane STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan ikkje byggje signaler her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan ikkje byggje jernbanespor her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan ikkje fjerne jernbanespor herfrå... diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 680caf1b20..0a37201449 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -3696,8 +3696,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Elementy kolei: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sygnalizatory STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Elementy dróg: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Droga -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramwaj STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Pola wody: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanały STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stacje: @@ -4734,7 +4732,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Należy STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nieodpowiednie tory/brak torów STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Należy najpierw usunąć tory STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Droga jest jednokierunkowa lub zablokowana -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Przejazd kolejowy nie dozwolony dla tego typu torów +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Przejazd kolejowy nie dozwolony dla tego typu torów STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nie można tutaj postawić sygnałów... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nie można tutaj ułożyć torów... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nie można stąd usunąć torów... diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 60b61821c1..8c43aadd84 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -3356,8 +3356,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Secções de caminho-de-ferro: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinais STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Secções de estrada: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Estrada -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Via para elétricos STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Blocos de água: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canais STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estações: @@ -4403,7 +4401,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Deverá STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tipo de linha não apropriado STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Deverá remover a linha férrea primeiro STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Estrada de sentido único ou bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Passagens de nível não são permitidas para este tipo de linha +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Passagens de nível não são permitidas para este tipo de linha STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Não é possível construir sinais aqui... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Não é possível construir linha férrea aqui... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Não é possível remover linha férrea daqui... diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index b9b5f1568d..931de0d19e 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -3238,8 +3238,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Pătrățele de cale ferată: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Semnale STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Pătrățele cu drumuri: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Drumuri -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvaie STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Suprafață apă: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canale STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stații: @@ -4252,7 +4250,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Trebuie STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Cale ferată nepotrivită STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Mai întâi trebuie înlăturată calea ferată STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Drum cu sens unic sau blocat -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Trecerea la nivel nu este permisă pentru acest tip de cale ferată +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Trecerea la nivel nu este permisă pentru acest tip de cale ferată STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nu se pot plasa semafoare aici... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nu se poate construi cale ferată aici... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nu se poate înlătura calea ferată... diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 87e60e8d6f..d190c0c336 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -3544,8 +3544,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Инфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Ж/д участки: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Сигналы STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Дорожные участки: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Автодороги -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамвайные пути STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Водные участки: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Каналы STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станции: @@ -4614,7 +4612,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Снач STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Нет подходящих рельсов STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Сначала удалите рельсы STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Дорога односторонняя или заблокирована -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Через этот вид рельсов запрещено строить переезды +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Через этот вид рельсов запрещено строить переезды STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Здесь невозможно поставить сигнал... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Здесь невозможно проложить рельсы... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Не удалось удалить рельсы... diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index c2119f2495..9731fb3f4f 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -3465,8 +3465,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Delova pruge: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalizacija STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Delova druma: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Drum -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajska pruga STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Pločica sa vodom: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: @@ -4510,7 +4508,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Neophodn STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nedostaje odgovarajuća železnička pruga STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Potrebno je prvo ukloniti železničku prugu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Put je jednosmeran ili je blokiran -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Putni prelaz nije dozvoljen za ovu vrstu pruge +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Putni prelaz nije dozvoljen za ovu vrstu pruge STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Izgradnja signalizacije ovde nije moguća... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Izgradnja železničke pruge ovde nije moguća... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nemoguće je ukloniti železničku prugu odatle... diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index dcfbe3ed03..e51df206a0 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -3279,8 +3279,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}铁路: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}信号灯 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}道路: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}普通道路 -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}电车线路 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}水运: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}运河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}站台: @@ -4305,7 +4303,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}必须 STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}没有合适的轨道 STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}必须先拆除轨道 STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}这是单行道或这条路被堵死了 -STR_ERROR_CROSSING_DISALLOWED :{WHITE}该轨道类型不允许建设平交道 +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}该轨道类型不允许建设平交道 STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}不能在这里设置信号灯…… STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}不能在这里铺设轨道…… STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}不能从这里拆除轨道…… diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index db236b0747..62784af6b8 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -3322,8 +3322,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrašt STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Políčka železnice: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Semafóry STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Políčka cesty: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Električka STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vodné políčka: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanále STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: @@ -4335,7 +4333,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprv j STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Žiadne použiteľné železničné koľaje STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Musíš najskôr odstrániť železničné koľaje STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je jednosmerná alebo blokovaná. -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Nie sú povolené priecestia pre tento typ železníc +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Nie sú povolené priecestia pre tento typ železníc STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nemôžeš tu stavať návestidlá... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nemôžeš tu stavať železničné koľaje... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nemôžeš tu odstrániť železničné koľaje... diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index 415c379f43..f91fad236f 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -3408,8 +3408,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Kosi tirov: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Odseki cest: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvaj STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Polja vode: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Postaje: @@ -4422,7 +4420,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprej STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ni primernih tračnic STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprej moraš odstraniti tračnice STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je enosmerna ali blokirana -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Istonivojna križišča niso dovoljena za ta tip železnice +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Istonivojna križišča niso dovoljena za ta tip železnice STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Tukaj ni mogoče zgraditi signalov... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Tukaj ni mogoče zgraditi železniških tirov... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Tukaj ni mogoče odstraniti železniških tirov... diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 86fb0c1c58..ec0d995004 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -3303,8 +3303,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Trozos de ferrocarril: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Señales STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Trozos de carretera: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Carretera -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tranvía STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Casillas de agua: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canales STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estaciones: @@ -4335,7 +4333,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Primero STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tramo de ferrocarril no apropiado STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Primero se debe retirar tramo de ferrocarril STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Carretera de un solo sentido o bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}No se permiten pasos a nivel para este tipo de ferrocarril +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}No se permiten pasos a nivel para este tipo de ferrocarril STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}No se pueden construir señales aquí... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}No se pueden construir ferrocarriles aquí... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}No se pueden retirar ferrocarriles aquí... diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index a7e080039f..0d28c27c3d 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -3357,8 +3357,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Tramos de vías férreas: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Señales STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Tramos de carretera: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Carretera -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tranvía STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Casillas de agua: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canales STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estaciones: @@ -4404,7 +4402,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Primero STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tramo de vías férreas no apropiado STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Primero se debe quitar el tramo de vías férreas STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Carretera de un solo sentido o bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}No se permiten pasos a nivel para este tipo de vías férreas +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}No se permiten pasos a nivel para este tipo de vías férreas STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}No se pueden instalar señales aquí... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}No se pueden construir vías férreas aquí... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}No se pueden quitar vías férreas de aquí... diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 3fa98f801e..488619d123 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -3333,8 +3333,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Järnvägsbitar: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vägbitar: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Väg -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Spårväg STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vattenrutor: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanaler STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationer: @@ -4368,7 +4366,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Måste t STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Inget passande järnvägsspår STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Måste ta bort järnväg först STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vägen är enkelriktad eller blockerad -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Plankorsningar är inte tillåtna för denna typ av spår +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Plankorsningar är inte tillåtna för denna typ av spår STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan inte bygga signaler här... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan inte bygga järnvägsspår här... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan inte ta bort järnvägspår här... diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index dd615ac090..473fba7f77 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -2879,8 +2879,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}இரயில் பாகங்கள்: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}சிக்னல்கள் STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}சாலை பாகங்கள்: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}சாலை -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}ட்ராம்வே STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}தண்ணீர் வட்டங்கள்: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}கால்வாய்கள் STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}நிலையங்கள்: @@ -3821,7 +3819,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}மு STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}தக்க இரயில் தடம் ஏதும் இல்லை STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}முதலில் இரயில்வே தடத்தினை எடுக்க வேண்டும் STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}சாலை ஒருவழிப்பாதை அல்லது மறிக்கப்பட்டுள்ளது -STR_ERROR_CROSSING_DISALLOWED :{WHITE}இந்த வகையிலான இரயில்களுக்கு இருப்புப்பாதை சந்திக் கடவுகள் கிடையாது +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}இந்த வகையிலான இரயில்களுக்கு இருப்புப்பாதை சந்திக் கடவுகள் கிடையாது STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}இங்கே சிக்னல்களை நிறுவ இயலாது... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}இங்கே இரயில்வே தடங்களை பதிய முடியாது... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}இங்கிருந்து இரயில்வே தடங்களை அகற்ற முடியாது... diff --git a/src/lang/thai.txt b/src/lang/thai.txt index c2c9eb9a2d..89e78f5e8f 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -3186,8 +3186,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}โค STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}ชิ้นส่วนทางรถไฟ: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}เสาอาณัติสัญญาณ STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}ชิ้นส่วนถนน: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}ถนน -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}ทางรถราง STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}คลอง: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}คลอง STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}สถานี: @@ -4180,7 +4178,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}ต้ STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}ไม่มีรางรถไฟที่เหมาะสม STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}ต้องทำลายทางรถไฟทิ้งเสียก่อน STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}ถนนเป็นทางเดียวหรือถูกปิดกั้น -STR_ERROR_CROSSING_DISALLOWED :{WHITE}ทางตัดเสมอระดับทางไม่อนุญาตให้ตัดผ่านทางประเภทนี้ +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}ทางตัดเสมอระดับทางไม่อนุญาตให้ตัดผ่านทางประเภทนี้ STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}ไม่สามารถสร้างเสาอาณัติสัญญาณได้... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}บริเวณนี้ไม่สามารถสร้างรางรถไฟได้... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}ตรงนี้ไม่สามารถลบรางรถไฟออกไปได้ diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index 8e23c03cd8..e754a40a24 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -3254,8 +3254,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}鐵路區塊: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}號誌 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}道路區塊: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}道路 -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}路面電車 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}水道或海運設施: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}運河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}車站: @@ -4267,7 +4265,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}必須 STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}沒有適合的鐵軌 STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}必須先移除鐵路 STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}道路是單行道或已封閉 -STR_ERROR_CROSSING_DISALLOWED :{WHITE}這種軌道不能建設平交道 +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}這種軌道不能建設平交道 STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}無法在此興建號誌... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}無法在此鋪設鐵路... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}不能從這邊移除鐵路... diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index f2d26db293..c15545d7be 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -3342,8 +3342,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Demiryolu parçaları: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinyaller STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Karayolu parçaları: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Karayolu -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvay STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Su kareleri: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanallar STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}İstasyonlar: @@ -4377,7 +4375,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Önce i STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Uygun ray yok STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Önce ray kaldırılmalı STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Yol tek yönlü veya kapalı -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Bu ray türü için hemzemin geçit yapılamaz +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Bu ray türü için hemzemin geçit yapılamaz STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Buraya sinyal yapılamıyor... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Buraya ray yapılamıyor... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Buradan ray kaldırılamıyor... diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index 4830c0e3d6..dd0930672b 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -3484,8 +3484,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Інфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Залізничні ділянки: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}З сигналами STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Дорожні ділянки: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Автомобільні -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамвайні STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Судноплавні ділянки: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Канали STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станції: @@ -4519,7 +4517,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Споч STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Невідповідний тип колії STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Спочатку приберіть колію STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Дорога з одностороннім рухом або блокована -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Переїзди для такого виду колії є забороненими +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Переїзди для такого виду колії є забороненими STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Неможливо будувати сигнали тут... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Неможливо будувати колію тут... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Неможливо прибрати колію звідси... diff --git a/src/lang/unfinished/frisian.txt b/src/lang/unfinished/frisian.txt index d9ecf58120..6b5afc40cc 100644 --- a/src/lang/unfinished/frisian.txt +++ b/src/lang/unfinished/frisian.txt @@ -3009,8 +3009,6 @@ STR_BUY_COMPANY_MESSAGE :{WHITE}Wy sykje STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Ynfrastruktuer fan {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seinen STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Stikjes dyk: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Dyk -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramwei STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasjons: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Stasjontegels STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Fleanfjilden @@ -3821,7 +3819,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Stopljoc STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Spoar is net geskikt STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Spoar moat der earst wei STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Dyk is in ienrjochtingsdyk of blokearre -STR_ERROR_CROSSING_DISALLOWED :{WHITE}In oergong is net tastien foar dit type spoar +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}In oergong is net tastien foar dit type spoar STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kin hjir gjin stopljochten boue... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kin hjir gjin spoarwei boue STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kin hjir gjin spoar fuorthelje... diff --git a/src/lang/unfinished/macedonian.txt b/src/lang/unfinished/macedonian.txt index 3039736660..dc54d04e89 100644 --- a/src/lang/unfinished/macedonian.txt +++ b/src/lang/unfinished/macedonian.txt @@ -1399,8 +1399,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Инфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}железнички парчиња: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}сигнали STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Патот парчиња: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}патот -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}трамвај STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Вода плочки: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}каналите STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}станици: @@ -1768,7 +1766,7 @@ STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Не а STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(лимит на пари) # Rail construction errors -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ниво, нема премини се дозволени за овој вид железнички +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ниво, нема премини се дозволени за овој вид железнички STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... не постои железничка пруга STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... постојат никакви сигнали diff --git a/src/lang/unfinished/persian.txt b/src/lang/unfinished/persian.txt index ddc7f01f11..7595fddb77 100644 --- a/src/lang/unfinished/persian.txt +++ b/src/lang/unfinished/persian.txt @@ -2875,8 +2875,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}زیرس STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}قطعه های ریل: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}نشانگرها STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}قطعه های راه: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}راه -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}تراموا STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}قسمتهای زیر آب: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}کانال ها STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}ایستگاه ها: diff --git a/src/lang/unfinished/urdu.txt b/src/lang/unfinished/urdu.txt index 2cbc96cd46..3973454b16 100644 --- a/src/lang/unfinished/urdu.txt +++ b/src/lang/unfinished/urdu.txt @@ -2302,8 +2302,6 @@ STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION :بتائیں آ STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}ریل کے ٹکڑے STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}اشارے STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}سڑک کے ٹکرے -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}سڑک -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}ٹرام وے STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}پانی کی ٹائل STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}نہریں STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD} اسٹیشن: diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 74fb67b395..0beeb0db98 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -3317,8 +3317,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Hạ t STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Ô đường ray: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Tín hiệu STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Ô đường bộ: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Đường bộ -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Xe điện STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Ô là nước: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kênh đào STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Ga, bến: @@ -4346,7 +4344,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Phải b STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Không có đường ray thích hợp STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Phải phá bỏ đường ray trước STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Đường một chiều hoặc bị chặn -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Đường giao nhau không cho phép với loại ray này +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Đường giao nhau không cho phép với loại ray này STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Không thể xây đèn hiệu ở đây... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Không thể xây đường ray ở đây... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Không thể phá bỏ đường ray ở đây... diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index d79c09510e..d7c83eca99 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -3258,8 +3258,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Tanadeil STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Darnau rheilffordd: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalau STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Darnau ffordd: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Ffordd -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramffordd STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Teiliau dŵr: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Camlesi STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Gorsafoedd: @@ -4286,7 +4284,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Rhaid ty STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Dim trac rheilffordd addas STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rhaid tynnu'r trac rheilffordd yn gyntaf STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Mae'r ffordd yn ffordd un-ffordd, neu wedi'i blocio -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ni chaniateir croesfannau ar y cledrau yma +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ni chaniateir croesfannau ar y cledrau yma STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Methu adeiladu signalau yma... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Methu adeiladu trac rheilffordd yma... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Methu tynnu trac rheilffordd oddi yma... diff --git a/src/map.cpp b/src/map.cpp index 0781ed47bd..b5fd750339 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -519,8 +519,8 @@ void DumpMapStats(char *b, const char *last) if (IsTunnelBridgeSignalSimulationBidirectional(t)) bucket |= TBB_SIGNALLED_BIDI; } if (GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD) { - if (HasTileRoadType(t, ROADTYPE_ROAD)) bucket |= TBB_ROAD; - if (HasTileRoadType(t, ROADTYPE_TRAM)) bucket |= TBB_TRAM; + if (HasTileRoadType(t, RTT_ROAD)) bucket |= TBB_ROAD; + if (HasTileRoadType(t, RTT_TRAM)) bucket |= TBB_TRAM; } if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) bucket |= TBB_RAIL; if (GetTunnelBridgeTransportType(t) == TRANSPORT_WATER) bucket |= TBB_WATER; diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index e2a5169bc3..563b5c9b08 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -177,7 +177,10 @@ public: td.railtype2 = STR_NULL; td.rail_speed = 0; td.rail_speed2 = 0; + td.roadtype = STR_NULL; td.road_speed = 0; + td.tramtype = STR_NULL; + td.tram_speed = 0; td.grf = nullptr; @@ -312,6 +315,13 @@ public: line_nr++; } + /* Road type name */ + if (td.roadtype != STR_NULL) { + SetDParam(0, td.roadtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + /* Road speed limit */ if (td.road_speed != 0) { SetDParam(0, td.road_speed); @@ -319,6 +329,20 @@ public: line_nr++; } + /* Tram type name */ + if (td.tramtype != STR_NULL) { + SetDParam(0, td.tramtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Tram speed limit */ + if (td.tram_speed != 0) { + SetDParam(0, td.tram_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + /* NewGRF name */ if (td.grf != nullptr) { SetDParamStr(0, td.grf); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 501571ada8..b73914c015 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -48,6 +48,7 @@ #include "vehicle_func.h" #include "language.h" #include "vehicle_base.h" +#include "road.h" #include "table/strings.h" #include "table/build_industry.h" @@ -313,6 +314,7 @@ struct GRFTempEngineData { uint16 cargo_allowed; uint16 cargo_disallowed; RailTypeLabel railtypelabel; + uint8 roadtramtype; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. bool prop27_set; ///< Did the NewGRF set property 27 (misc flags)? @@ -1380,6 +1382,12 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop RoadVehicleInfo *rvi = &e->u.road; switch (prop) { + case 0x05: // Road/tram type + /* RoadTypeLabel is looked up later after the engine's road/tram + * flag is set, however 0 means the value has not been set. */ + _gted[e->index].roadtramtype = buf->ReadByte() + 1; + break; + case 0x08: // Speed (1 unit is 0.5 kmh) rvi->max_speed = buf->ReadByte(); break; @@ -2686,6 +2694,12 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, co case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -2901,6 +2915,12 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, c case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -4442,6 +4462,228 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, cons return ret; } +/** + * Define properties for roadtypes + * @param id ID of the roadtype. + * @param numinfo Number of subsequent IDs to change the property for. + * @param prop The property to change. + * @param buf The property value. + * @return ChangeInfoResult. + */ +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeChangeInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + RoadType rt = type_map[id + i]; + if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID; + + RoadTypeInfo *rti = &_roadtypes[rt]; + + switch (prop) { + case 0x08: // Label of road type + /* Skipped here as this is loaded during reservation stage. */ + buf->ReadDWord(); + break; + + case 0x09: { // Toolbar caption of roadtype (sets name as well for backwards compatibility for grf ver < 8) + uint16 str = buf->ReadWord(); + AddStringForMapping(str, &rti->strings.toolbar_caption); + break; + } + + case 0x0A: // Menu text of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.menu_text); + break; + + case 0x0B: // Build window caption + AddStringForMapping(buf->ReadWord(), &rti->strings.build_caption); + break; + + case 0x0C: // Autoreplace text + AddStringForMapping(buf->ReadWord(), &rti->strings.replace_text); + break; + + case 0x0D: // New engine text + AddStringForMapping(buf->ReadWord(), &rti->strings.new_engine); + break; + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: { // Introduced roadtype list + /* Road type compatibility bits are added to the existing bits + * to allow multiple GRFs to modify compatibility with the + * default road types. */ + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + RoadTypeLabel label = buf->ReadDWord(); + RoadType rt = GetRoadTypeByLabel(BSWAP32(label), false); + if (rt != INVALID_ROADTYPE) { + switch (prop) { + case 0x0F: SetBit(rti->powered_roadtypes, rt); break; + case 0x18: SetBit(rti->introduction_required_roadtypes, rt); break; + case 0x19: SetBit(rti->introduces_roadtypes, rt); break; + } + } + } + break; + } + + case 0x10: // Road Type flags + rti->flags = (RoadTypeFlags)buf->ReadByte(); + break; + + case 0x13: // Construction cost factor + rti->cost_multiplier = buf->ReadWord(); + break; + + case 0x14: // Speed limit + rti->max_speed = buf->ReadWord(); + break; + + case 0x16: // Map colour + rti->map_colour = buf->ReadByte(); + break; + + case 0x17: // Introduction date + rti->introduction_date = buf->ReadDWord(); + break; + + case 0x1A: // Sort order + rti->sorting_order = buf->ReadByte(); + break; + + case 0x1B: // Name of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.name); + break; + + case 0x1C: // Maintenance cost factor + rti->maintenance_multiplier = buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + /* Skipped here as this is loaded during reservation stage. */ + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, mapping_entry, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, mapping_entry, buf, RTT_TRAM); +} + + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + switch (prop) { + case 0x08: { // Label of road type + RoadTypeLabel rtl = buf->ReadDWord(); + rtl = BSWAP32(rtl); + + RoadType rt = GetRoadTypeByLabel(rtl, false); + if (rt == INVALID_ROADTYPE) { + /* Set up new road type */ + rt = AllocateRoadType(rtl, rtt); + } else if (GetRoadTramType(rt) != rtt) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid type (road/tram), ignoring", id + numinfo); + return CIR_INVALID_ID; + } + + type_map[id + i] = rt; + break; + } + case 0x09: // Toolbar caption of roadtype + case 0x0A: // Menu text + case 0x0B: // Build window caption + case 0x0C: // Autoreplace text + case 0x0D: // New loco + case 0x13: // Construction cost + case 0x14: // Speed limit + case 0x1B: // Name of roadtype + case 0x1C: // Maintenance cost factor + buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + if (type_map[id + i] != INVALID_ROADTYPE) { + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + _roadtypes[type_map[id + i]].alternate_labels.push_back(BSWAP32(buf->ReadDWord())); + } + break; + } + grfmsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type %u because no label was set", id + i); + /* FALL THROUGH */ + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: // Introduced roadtype list + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + case 0x10: // Road Type flags + case 0x12: // Station graphic + case 0x15: // Acceleration model + case 0x16: // Map colour + case 0x1A: // Sort order + buf->ReadByte(); + break; + + case 0x17: // Introduction date + buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, mapping_entry, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeReserveInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, mapping_entry, buf, RTT_TRAM); +} + static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; @@ -4626,6 +4868,8 @@ static void FeatureChangeInfo(ByteReader *buf) /* GSF_OBJECTS */ ObjectChangeInfo, /* GSF_RAILTYPES */ RailTypeChangeInfo, /* GSF_AIRPORTTILES */ AirportTilesChangeInfo, + /* GSF_ROADTYPES */ RoadTypeChangeInfo, + /* GSF_TRAMTYPES */ TramTypeChangeInfo, }; static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch"); @@ -4700,7 +4944,7 @@ static void ReserveChangeInfo(ByteReader *buf) { uint8 feature = buf->ReadByte(); - if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES) return; + if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return; uint8 numprops = buf->ReadByte(); uint8 numinfo = buf->ReadByte(); @@ -4723,6 +4967,14 @@ static void ReserveChangeInfo(ByteReader *buf) case GSF_RAILTYPES: cir = RailTypeReserveInfo(index, numinfo, desc.prop, desc.entry, buf); break; + + case GSF_ROADTYPES: + cir = RoadTypeReserveInfo(index, numinfo, desc.prop, desc.entry, buf); + break; + + case GSF_TRAMTYPES: + cir = TramTypeReserveInfo(index, numinfo, desc.prop, desc.entry, buf); + break; } if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, desc.prop)) return; @@ -5035,6 +5287,8 @@ static void NewSpriteGroup(ByteReader *buf) case GSF_CARGOES: case GSF_AIRPORTS: case GSF_RAILTYPES: + case GSF_ROADTYPES: + case GSF_TRAMTYPES: { byte num_loaded = type; byte num_loading = buf->ReadByte(); @@ -5612,6 +5866,39 @@ static void RailTypeMapSpriteGroup(ByteReader *buf, uint8 idcount) buf->ReadWord(); } +static void RoadTypeMapSpriteGroup(ByteReader *buf, uint8 idcount, RoadTramType rtt) +{ + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + uint8 *roadtypes = AllocaM(uint8, idcount); + for (uint i = 0; i < idcount; i++) { + uint8 id = buf->ReadByte(); + roadtypes[i] = id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE; + } + + uint8 cidcount = buf->ReadByte(); + for (uint c = 0; c < cidcount; c++) { + uint8 ctype = buf->ReadByte(); + uint16 groupid = buf->ReadWord(); + if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue; + + if (ctype >= ROTSG_END) continue; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + for (uint i = 0; i < idcount; i++) { + if (roadtypes[i] != INVALID_ROADTYPE) { + RoadTypeInfo *rti = &_roadtypes[roadtypes[i]]; + + rti->grffile[ctype] = _cur.grffile; + rti->group[ctype] = _cur.spritegroups[groupid]; + } + } + } + + /* Roadtypes do not use the default group. */ + buf->ReadWord(); +} + static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *airports = AllocaM(uint8, idcount); @@ -5762,6 +6049,14 @@ static void FeatureMapSpriteGroup(ByteReader *buf) RailTypeMapSpriteGroup(buf, idcount); break; + case GSF_ROADTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD); + break; + + case GSF_TRAMTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM); + break; + case GSF_AIRPORTTILES: AirportTileMapSpriteGroup(buf, idcount); return; @@ -6030,6 +6325,15 @@ static void GraphicsNew(ByteReader *buf) /* Load sprites starting from , then skip sprites. */ grfmsg(2, "GraphicsNew: Replacing sprites %d to %d of %s (type 0x%02X) at SpriteID 0x%04X", offset, offset + num - 1, action5_type->name, type, replace); + if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; + + if (type == 0x0B) { + static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE; + static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE; + if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK; + if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK; + } + for (uint16 n = num; n > 0; n--) { _cur.nfo_line++; LoadNextSprite(replace == 0 ? _cur.spriteid++ : replace++, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); @@ -6043,8 +6347,6 @@ static void GraphicsNew(ByteReader *buf) } } - if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; - _cur.skip_sprites = skip_num; } @@ -6468,6 +6770,14 @@ static void SkipIf(ByteReader *buf) break; case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE; break; + case 0x0F: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x10: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; + case 0x11: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x12: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; default: grfmsg(1, "SkipIf: Unsupported condition type %02X. Ignoring", condtype); return; } @@ -8830,6 +9140,9 @@ void ResetNewGRFData() /* Reset rail type information */ ResetRailTypes(); + /* Copy/reset original road type info data */ + ResetRoadTypes(); + /* Allocate temporary refit/cargo class data */ _gted = CallocT(Engine::GetPoolSize()); @@ -8898,6 +9211,7 @@ void ResetNewGRFData() _loaded_newgrf_features.has_newhouses = false; _loaded_newgrf_features.has_newindustries = false; _loaded_newgrf_features.shore = SHORE_REPLACE_NONE; + _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NONE; /* Clear all GRF overrides */ _grf_id_overrides.clear(); @@ -8985,6 +9299,14 @@ GRFFile::GRFFile(const GRFConfig *config) this->railtype_map[2] = RAILTYPE_MONO; this->railtype_map[3] = RAILTYPE_MAGLEV; + /* Initialise road type map with default road types */ + memset(this->roadtype_map, INVALID_ROADTYPE, sizeof(this->roadtype_map)); + this->roadtype_map[0] = ROADTYPE_ROAD; + + /* Initialise tram type map with default tram types */ + memset(this->tramtype_map, INVALID_ROADTYPE, sizeof(this->tramtype_map)); + this->tramtype_map[0] = ROADTYPE_TRAM; + /* Copy the initial parameter list * 'Uninitialised' parameters are zeroed as that is their default value when dynamically creating them. */ assert_compile(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80); @@ -9754,6 +10076,21 @@ static void ActivateOldShore() } } +/** + * Replocate the old tram depot sprites to the new position, if no new ones were loaded. + */ +static void ActivateOldTramDepot() +{ + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK) { + DupSprite(SPR_ROAD_DEPOT + 0, SPR_TRAMWAY_DEPOT_NO_TRACK + 0); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 1, SPR_TRAMWAY_DEPOT_NO_TRACK + 1); + DupSprite(SPR_ROAD_DEPOT + 2, SPR_TRAMWAY_DEPOT_NO_TRACK + 2); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 3, SPR_TRAMWAY_DEPOT_NO_TRACK + 3); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 4, SPR_TRAMWAY_DEPOT_NO_TRACK + 4); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 5, SPR_TRAMWAY_DEPOT_NO_TRACK + 5); + } +} + /** * Decide whether price base multipliers of grfs shall apply globally or only to the grf specifying them */ @@ -9932,8 +10269,12 @@ static void AfterLoadGRFs() /* Load old shore sprites in new position, if they were replaced by ActionA */ ActivateOldShore(); + /* Load old tram depot sprites in new position, if no new ones are present */ + ActivateOldTramDepot(); + /* Set up custom rail types */ InitRailTypes(); + InitRoadTypes(); Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { @@ -9941,6 +10282,31 @@ static void AfterLoadGRFs() /* Set RV maximum speed from the mph/0.8 unit value */ e->u.road.max_speed = _gted[e->index].rv_max_speed * 4; } + + RoadTramType rtt = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? RTT_TRAM : RTT_ROAD; + + const GRFFile *file = e->GetGRF(); + if (file == nullptr || _gted[e->index].roadtramtype == 0) { + e->u.road.roadtype = (rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; + continue; + } + + /* Remove +1 offset. */ + _gted[e->index].roadtramtype--; + + const std::vector *list = (rtt == RTT_TRAM) ? &file->tramtype_list : &file->roadtype_list; + if (_gted[e->index].roadtramtype < list->size()) + { + RoadTypeLabel rtl = (*list)[_gted[e->index].roadtramtype]; + RoadType rt = GetRoadTypeByLabel(rtl); + if (rt != INVALID_ROADTYPE && GetRoadTramType(rt) == rtt) { + e->u.road.roadtype = rt; + continue; + } + } + + /* Road type is not available, so disable this engine */ + e->info.climates = 0; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { diff --git a/src/newgrf.h b/src/newgrf.h index 1a0b592ee4..ef6b50faaa 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -14,6 +14,7 @@ #include "cargotype.h" #include "rail_type.h" +#include "road_type.h" #include "fileio_type.h" #include "debug.h" #include "core/bitmath_func.hpp" @@ -86,6 +87,8 @@ enum GrfSpecFeature { GSF_OBJECTS, GSF_RAILTYPES, GSF_AIRPORTTILES, + GSF_ROADTYPES, + GSF_TRAMTYPES, GSF_END, GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope) @@ -240,6 +243,12 @@ struct GRFFile : ZeroedMemoryAllocator { std::vector railtype_list; ///< Railtype translation table RailType railtype_map[RAILTYPE_END]; + std::vector roadtype_list; ///< Roadtype translation table (road) + RoadType roadtype_map[ROADTYPE_END]; + + std::vector tramtype_list; ///, Roadtype translation table (tram) + RoadType tramtype_map[ROADTYPE_END]; + CanalProperties canal_local_properties[CF_END]; ///< Canal properties as set by this NewGRF struct LanguageMap *language_map; ///< Mappings related to the languages. @@ -273,12 +282,19 @@ enum ShoreReplacement { SHORE_REPLACE_ONLY_NEW, ///< Only corner-shores were loaded by Action5 (openttd(w/d).grf only). }; +enum TramReplacement { + TRAMWAY_REPLACE_DEPOT_NONE, ///< No tram depot graphics were loaded. + TRAMWAY_REPLACE_DEPOT_WITH_TRACK, ///< Electrified depot graphics with tram track were loaded. + TRAMWAY_REPLACE_DEPOT_NO_TRACK, ///< Electrified depot graphics without tram track were loaded. +}; + struct GRFLoadedFeatures { bool has_2CC; ///< Set if any vehicle is loaded which uses 2cc (two company colours). uint64 used_liveries; ///< Bitmask of #LiveryScheme used by the defined engines. bool has_newhouses; ///< Set if there are any newhouses loaded. bool has_newindustries; ///< Set if there are any newindustries loaded. ShoreReplacement shore; ///< In which way shore sprites were replaced. + TramReplacement tram; ///< In which way tram depots were replaced. }; /** diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index e997138f4d..bd93829867 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -23,6 +23,7 @@ #include "station_base.h" #include "company_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "ship.h" #include "safeguards.h" @@ -606,12 +607,22 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, case 0x48: return v->GetEngine()->flags; // Vehicle Type Info case 0x49: return v->build_year; - case 0x4A: { - if (v->type != VEH_TRAIN) return 0; - if (Train::From(v)->IsVirtual()) return 0x1FF; - RailType rt = GetTileRailTypeByTrackBit(v->tile, Train::From(v)->track); - return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile); - } + case 0x4A: + switch (v->type) { + case VEH_TRAIN: { + if (Train::From(v)->IsVirtual()) return 0x1FF; + RailType rt = GetTileRailTypeByTrackBit(v->tile, Train::From(v)->track); + return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile); + } + + case VEH_ROAD: { + RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype)); + return 0x100 | GetReverseRoadTypeTranslation(rt, object->ro.grffile); + } + + default: + return 0; + } case 0x4B: // Long date of last service return v->date_of_last_service; diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp new file mode 100644 index 0000000000..1fb8e5ec1a --- /dev/null +++ b/src/newgrf_roadtype.cpp @@ -0,0 +1,143 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_roadtype.cpp NewGRF handling of road types. */ + +#include "stdafx.h" +#include "debug.h" +#include "newgrf_roadtype.h" +#include "date_func.h" +#include "depot_base.h" +#include "town.h" + +#include "safeguards.h" + +/* virtual */ uint32 RoadTypeScopeResolver::GetRandomBits() const +{ + uint tmp = CountBits(this->tile + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); + return GB(tmp, 0, 2); +} + +/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +{ + if (this->tile == INVALID_TILE) { + switch (variable) { + case 0x40: return 0; + case 0x41: return 0; + case 0x42: return 0; + case 0x43: return _date; + case 0x44: return HZB_TOWN_EDGE; + } + } + + switch (variable) { + case 0x40: return GetTerrainType(this->tile, this->context); + case 0x41: return 0; + case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile); + case 0x43: + if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date; + return _date; + case 0x44: { + const Town *t = nullptr; + if (IsRoadDepotTile(this->tile)) { + t = Depot::GetByTile(this->tile)->town; + } else if (IsTileType(this->tile, MP_ROAD)) { + t = ClosestTownFromTile(this->tile, UINT_MAX); + } + return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; + } + } + + DEBUG(grf, 1, "Unhandled road type tile variable 0x%X", variable); + + *available = false; + return UINT_MAX; +} + +/* virtual */ const SpriteGroup *RoadTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const +{ + if (group->num_loading > 0) return group->loading[0]; + if (group->num_loaded > 0) return group->loaded[0]; + return nullptr; +} + +/** + * Constructor of the roadtype scope resolvers. + * @param ro Surrounding resolver. + * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. + * @param context Are we resolving sprites for the upper halftile, or on a bridge? + */ +RoadTypeScopeResolver::RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context) : ScopeResolver(ro) +{ + this->tile = tile; + this->context = context; +} + +/** + * Resolver object for road types. + * @param rti Roadtype. nullptr in NewGRF Inspect window. + * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. + * @param context Are we resolving sprites for the upper halftile, or on a bridge? + * @param rtsg Roadpart of interest + * @param param1 Extra parameter (first parameter of the callback, except roadtypes do not have callbacks). + * @param param2 Extra parameter (second parameter of the callback, except roadtypes do not have callbacks). + */ +RoadTypeResolverObject::RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1, uint32 param2) + : ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), roadtype_scope(*this, tile, context) +{ + this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr; +} + +/** + * Get the sprite to draw for the given tile. + * @param rti The road type data (spec). + * @param tile The tile to get the sprite for. + * @param rtsg The type of sprite to draw. + * @param content Where are we drawing the tile? + * @param [out] num_results If not nullptr, return the number of sprites in the spriteset. + * @return The sprite to draw. + */ +SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results) +{ + assert(rtsg < ROTSG_END); + + if (rti->group[rtsg] == nullptr) return 0; + + RoadTypeResolverObject object(rti, tile, context, rtsg); + const SpriteGroup *group = object.Resolve(); + if (group == nullptr || group->GetNumResults() == 0) return 0; + + if (num_results) *num_results = group->GetNumResults(); + + return group->GetResult(); +} + +/** + * Perform a reverse roadtype lookup to get the GRF internal ID. + * @param roadtype The global (OpenTTD) roadtype. + * @param grffile The GRF to do the lookup for. + * @return the GRF internal ID. + */ +uint8 GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile) +{ + /* No road type table present, return road type as-is */ + if (grffile == nullptr) return roadtype; + + const std::vector *list = RoadTypeIsRoad(roadtype) ? &grffile->roadtype_list : &grffile->tramtype_list; + if (list->size() == 0) return roadtype; + + /* Look for a matching road type label in the table */ + RoadTypeLabel label = GetRoadTypeInfo(roadtype)->label; + + int index = find_index(*list, label); + if (index >= 0) return index; + + /* If not found, return as invalid */ + return 0xFF; +} diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h new file mode 100644 index 0000000000..2da7a82c1f --- /dev/null +++ b/src/newgrf_roadtype.h @@ -0,0 +1,51 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_roadtype.h NewGRF handling of road types. */ + +#ifndef NEWGRF_ROADTYPE_H +#define NEWGRF_ROADTYPE_H + +#include "road.h" +#include "newgrf_commons.h" +#include "newgrf_spritegroup.h" + +/** Resolver for the railtype scope. */ +struct RoadTypeScopeResolver : public ScopeResolver { + TileIndex tile; ///< Tracktile. For track on a bridge this is the southern bridgehead. + TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge? + + RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context); + + /* virtual */ uint32 GetRandomBits() const; + /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; +}; + +/** Resolver object for road types. */ +struct RoadTypeResolverObject : public ResolverObject { + RoadTypeScopeResolver roadtype_scope; ///< Resolver for the roadtype scope. + + RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1 = 0, uint32 param2 = 0); + + /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + { + switch (scope) { + case VSG_SCOPE_SELF: return &this->roadtype_scope; + default: return ResolverObject::GetScope(scope, relative); + } + } + + /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; +}; + +SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr); + +uint8 GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile); + +#endif /* NEWGRF_ROADTYPE_H */ diff --git a/src/openttd.cpp b/src/openttd.cpp index af2b02082f..4b4ecb132a 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -53,6 +53,7 @@ #include "engine_func.h" #include "core/random_func.hpp" #include "rail_gui.h" +#include "road_gui.h" #include "core/backup_type.hpp" #include "hotkeys.h" #include "newgrf.h" @@ -1040,6 +1041,7 @@ static void MakeNewGameDone() SetLocalCompany(COMPANY_FIRST); InitializeRailGUI(); + InitializeRoadGUI(); /* We are the server, we start a new company (not dedicated), * so set the default password *if* needed. */ diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index db990501d4..827499a894 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -33,7 +33,7 @@ struct CFollowTrackT enum ErrorCode { EC_NONE, EC_OWNER, - EC_RAIL_TYPE, + EC_RAIL_ROAD_TYPE, EC_90DEG, EC_NO_WAY, EC_RESERVED, @@ -61,6 +61,7 @@ struct CFollowTrackT inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr) { + assert(IsRailTT()); m_veh = nullptr; Init(o, railtype_override, pPerf); } @@ -93,7 +94,7 @@ struct CFollowTrackT inline static TransportType TT() { return Ttr_type_; } inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; } inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; } - inline bool IsTram() { return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM); } + inline bool IsTram() { return IsRoadTT() && RoadTypeIsTram(RoadVehicle::From(m_veh)->roadtype); } inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; } inline static bool Allow90degTurns() { return T90deg_turns_allowed_; } inline static bool DoTrackMasking() { return Tmask_reserved_tracks; } @@ -105,7 +106,7 @@ struct CFollowTrackT const bool is_bridge = IsRoadCustomBridgeHeadTile(tile); if (is_bridge || IsNormalRoadTile(tile)) { - RoadBits rb = is_bridge ? GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM) : GetRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = is_bridge ? GetCustomBridgeHeadRoadBits(tile, RTT_TRAM) : GetRoadBits(tile, RTT_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; @@ -128,7 +129,7 @@ struct CFollowTrackT m_err = EC_NONE; assert_tile( ((TrackStatusToTrackdirBits( - GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != nullptr) ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0) + GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != nullptr) ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0) ) & TrackdirToTrackdirBits(m_old_td)) != 0) || (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR), // Disable the assertion for single tram bits m_old_tile @@ -154,7 +155,7 @@ struct CFollowTrackT if (IsRoadTT() && !IsTram() && TryReverse()) return true; /* CanEnterNewTile already set a reason. - * Do NOT overwrite it (important for example for EC_RAIL_TYPE). + * Do NOT overwrite it (important for example for EC_RAIL_ROAD_TYPE). * Only set a reason if CanEnterNewTile was not called */ if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY; @@ -244,7 +245,7 @@ protected: if (IsRailTT() && IsPlainRailTile(m_new_tile)) { m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101); } else { - m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)); + m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0)); if (IsTram() && m_new_td_bits == TRACKDIR_BIT_NONE) { /* GetTileTrackStatus() returns 0 for single tram bits. @@ -358,7 +359,18 @@ protected: RailType rail_type = GetTileRailTypeByEntryDir(m_new_tile, m_exitdir); if (!HasBit(m_railtypes, rail_type)) { /* incompatible rail type */ - m_err = EC_RAIL_TYPE; + m_err = EC_RAIL_ROAD_TYPE; + return false; + } + } + + /* road transport is possible only on compatible road types */ + if (IsRoadTT()) { + const RoadVehicle *v = RoadVehicle::From(m_veh); + RoadType roadtype = GetRoadType(m_new_tile, GetRoadTramType(v->roadtype)); + if (!HasBit(v->compatible_roadtypes, roadtype)) { + /* incompatible road type */ + m_err = EC_RAIL_ROAD_TYPE; return false; } } @@ -380,7 +392,7 @@ protected: return false; } if (!m_is_bridge && IsRoadTT() && IsRoadCustomBridgeHeadTile(m_new_tile)) { - if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) { + if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? RTT_TRAM : RTT_ROAD))) { m_err = EC_NO_WAY; return false; } diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index 606652df39..13f9f94e19 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -44,6 +44,7 @@ struct AyStarUserData { TransportType type; RailTypes railtypes; RoadTypes roadtypes; + uint subtype; }; /** Indices into AyStarNode.userdata[] */ @@ -726,7 +727,7 @@ static DiagDirection GetDepotDirection(TileIndex tile, TransportType type) static DiagDirection GetSingleTramBit(TileIndex tile) { if (IsNormalRoadTile(tile)) { - RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = GetRoadBits(tile, RTT_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; @@ -754,7 +755,7 @@ static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint if (type == TRANSPORT_ROAD) { if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile); - if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile); + if ((RoadTramType)subtype == RTT_TRAM) return GetSingleTramBit(tile); } return INVALID_DIAGDIR; @@ -792,13 +793,24 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user if (!CanEnterTileOwnerCheck(user->owner, tile, dir)) return false; /* check correct rail type (mono, maglev, etc) */ - if (user->type == TRANSPORT_RAIL) { - RailType rail_type = GetTileRailTypeByEntryDir(tile, dir); - if (!HasBit(user->railtypes, rail_type)) return false; + switch (user->type) { + case TRANSPORT_RAIL: { + RailType rail_type = GetTileRailTypeByEntryDir(tile, dir); + if (!HasBit(user->railtypes, rail_type)) return false; + break; + } + + case TRANSPORT_ROAD: { + RoadType road_type = GetRoadType(tile, (RoadTramType)user->subtype); + if (!HasBit(user->roadtypes, road_type)) return false; + break; + } + + default: break; } /* Depots, standard roadstops and single tram bits can only be entered from one direction */ - DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->roadtypes); + DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->subtype); if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false; return true; @@ -820,7 +832,7 @@ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, TileIndex src_t { TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype)); - if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) { + if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && (RoadTramType)subtype == RTT_TRAM) { /* GetTileTrackStatus() returns 0 for single tram bits. * As we cannot change it there (easily) without breaking something, change it here */ switch (GetSingleTramBit(dst_tile)) { @@ -870,7 +882,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */ TransportType type = user->type; - uint subtype = user->roadtypes; + uint subtype = user->subtype; /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */ aystar->num_neighbours = 0; @@ -901,11 +913,11 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* We leave src_tile in src_exitdir and reach dst_tile */ dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir)); - if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE; + if (dst_tile != INVALID_TILE && IsNormalRoadTile(dst_tile) && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE; if (dst_tile == INVALID_TILE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ - if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; + if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); @@ -915,7 +927,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) if (trackdirbits == TRACKDIR_BIT_NONE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ - if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; + if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); @@ -1127,7 +1139,7 @@ FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penal { Trackdir trackdir = v->GetVehicleTrackdir(); - AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes }; + AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) }; NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, INVALID_TILE, INVALID_TRACKDIR, false, nullptr, &user, 0, max_penalty); if (ftd.best_bird_dist != 0) return FindDepotData(); @@ -1147,7 +1159,7 @@ Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDir NPFFillWithOrderData(&fstd, v); Trackdir trackdir = DiagDirToDiagTrackdir(enterdir); - AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes }; + AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, &user); assert(ftd.best_trackdir != INVALID_TRACKDIR); @@ -1170,7 +1182,7 @@ Track NPFShipChooseTrack(const Ship *v, bool &path_found) NPFFillWithOrderData(&fstd, v); - AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(v->tile, trackdir, true, &fstd, &user); /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains @@ -1194,7 +1206,7 @@ bool NPFShipCheckReverse(const Ship *v) assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 }; ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, v->tile, trackdir_rev, false, &fstd, &user); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); @@ -1212,7 +1224,7 @@ FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty) fstd.reserve_path = false; assert(trackdir != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user, NPF_INFINITE_PENALTY, max_penalty); if (ftd.best_bird_dist != 0) return FindDepotData(); @@ -1241,7 +1253,7 @@ bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackd /* perform a breadth first search. Target is nullptr, * since we are just looking for any safe tile...*/ - AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE, 0 }; return NPFRouteInternal(&start1, true, nullptr, false, &fstd, NPFFindSafeTile, NPFCalcZero, &user, 0, true).res_okay; } @@ -1258,7 +1270,7 @@ bool NPFTrainCheckReverse(const Train *v) assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); @@ -1272,7 +1284,7 @@ Track NPFTrainChooseTrack(const Train *v, bool &path_found, bool reserve_track, PBSTileInfo origin = FollowTrainReservation(v); assert(IsValidTrackdir(origin.trackdir)); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, &user); if (target != nullptr) { diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 23402c2483..fddaf96a3b 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -652,7 +652,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th if (!tf_local.Follow(cur.tile, cur.td)) { assert(tf_local.m_err != TrackFollower::EC_NONE); /* Can't move to the next tile (EOL?). */ - if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) { + if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) { end_segment_reason |= ESRB_RAIL_TYPE; } else { end_segment_reason |= ESRB_DEAD_END; diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp index 27e0b49655..728bc7065c 100644 --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -263,7 +263,7 @@ public: } else { m_dest_station = INVALID_STATION; m_destTile = v->dest_tile; - m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes)); + m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))); } } @@ -386,7 +386,7 @@ public: /* our source tile will be the next vehicle tile (should be the given one) */ TileIndex src_tile = tile; /* get available trackdirs on the start tile */ - TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)); + TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))); /* select reachable trackdirs only */ src_trackdirs &= DiagdirReachesTrackdirs(enterdir); @@ -485,7 +485,7 @@ public: /* set origin (tile, trackdir) */ TileIndex src_tile = v->tile; Trackdir src_td = v->GetVehicleTrackdir(); - if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)), src_td)) { + if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, this->IsTram() ? RTT_TRAM : RTT_ROAD)), src_td)) { /* sometimes the roadveh is not on the road (it resides on non-existing track) * how should we handle that situation? */ return false; @@ -565,7 +565,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist { TileIndex tile = v->tile; Trackdir trackdir = v->GetVehicleTrackdir(); - if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)), trackdir)) { + if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))), trackdir)) { return FindDepotData(); } diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index e61af4161f..4d620644be 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -675,41 +675,48 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD); - if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_RAIL); - RoadTypes roadtypes = GetRoadTypes(tile); - RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD); - RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM); + RoadType roadtype_road = GetRoadTypeRoad(tile); + RoadType roadtype_tram = GetRoadTypeTram(tile); + + if (roadtype_road != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_road)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + if (roadtype_tram != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_tram)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + + RoadBits road = GetRoadBits(tile, RTT_ROAD); + RoadBits tram = GetRoadBits(tile, RTT_TRAM); if ((track == TRACK_X && ((road | tram) & ROAD_X) == 0) || (track == TRACK_Y && ((road | tram) & ROAD_Y) == 0)) { - Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + Owner road_owner = GetRoadOwner(tile, RTT_ROAD); + Owner tram_owner = GetRoadOwner(tile, RTT_TRAM); /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ if (Company::IsValidID(tram_owner) && HasExactlyOneBit(tram)) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } - /* Crossings must always have a road... */ - uint num_new_road_pieces = 2 - CountBits(road); - if (road == ROAD_NONE) road_owner = _current_company; - roadtypes |= ROADTYPES_ROAD; - /* ...but tram is not required. */ - uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0; - cost.AddCost((num_new_road_pieces + num_new_tram_pieces) * _price[PR_BUILD_ROAD]); + uint num_new_road_pieces = (road != ROAD_NONE) ? 2 - CountBits(road) : 0; + if (num_new_road_pieces > 0) { + cost.AddCost(num_new_road_pieces * RoadBuildCost(roadtype_road)); + } + + uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0; + if (num_new_tram_pieces > 0) { + cost.AddCost(num_new_tram_pieces * RoadBuildCost(roadtype_tram)); + } if (flags & DC_EXEC) { - MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile)); + MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtype_road, roadtype_tram, GetTownIndex(tile)); UpdateLevelCrossing(tile, false); Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(_current_company); if (num_new_road_pieces > 0 && Company::IsValidID(road_owner)) { - Company::Get(road_owner)->infrastructure.road[ROADTYPE_ROAD] += num_new_road_pieces; + Company::Get(road_owner)->infrastructure.road[roadtype_road] += num_new_road_pieces; DirtyCompanyInfrastructureWindows(road_owner); } if (num_new_tram_pieces > 0 && Company::IsValidID(tram_owner)) { - Company::Get(tram_owner)->infrastructure.road[ROADTYPE_TRAM] += num_new_tram_pieces; + Company::Get(tram_owner)->infrastructure.road[roadtype_tram] += num_new_tram_pieces; DirtyCompanyInfrastructureWindows(tram_owner); } } @@ -811,10 +818,11 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, v = GetTrainForReservation(tile, track); if (v != nullptr) FreeTrainTrackReservation(v); } + owner = GetTileOwner(tile); Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(owner); - MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM)); + MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypeRoad(tile), GetRoadTypeTram(tile), GetTownIndex(tile), GetRoadOwner(tile, RTT_ROAD), GetRoadOwner(tile, RTT_TRAM)); DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile); } break; @@ -2048,7 +2056,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case MP_ROAD: if (!IsLevelCrossing(tile)) continue; if (RailNoLevelCrossings(totype)) { - error.MakeError(STR_ERROR_CROSSING_DISALLOWED); + error.MakeError(STR_ERROR_CROSSING_DISALLOWED_RAIL); continue; } break; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 96544ae65e..6cdb4c17dc 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -2235,5 +2235,11 @@ DropDownList GetRailTypeDropDownList(bool for_replacement, bool all_option) item->SetParam(1, rti->max_speed); list.emplace_back(item); } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, INVALID_RAILTYPE, true)); + } + return list; } diff --git a/src/road.cpp b/src/road.cpp index 1b5f3c2d75..f6d1ffe531 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -19,6 +19,9 @@ #include "engine_base.h" #include "date_func.h" #include "landscape.h" +#include "road.h" +#include "road_func.h" +#include "roadveh.h" #include "safeguards.h" @@ -75,7 +78,7 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) /* Always connective */ connective = true; } else { - const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, ROADTYPE_TRAM); + const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, RTT_ROAD) | GetAnyRoadBits(neighbor_tile, RTT_TRAM); /* Accept only connective tiles */ connective = (neighbor_rb & mirrored_rb) != ROAD_NONE; @@ -110,53 +113,236 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) } /** - * Finds out, whether given company has all given RoadTypes available + * Finds out, whether given company has a given RoadType available for construction. * @param company ID of company - * @param rts RoadTypes to test - * @return true if company has all requested RoadTypes available + * @param roadtypet RoadType to test + * @return true if company has the requested RoadType available */ -bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts) +bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype) { - RoadTypes avail_roadtypes; - if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) { - avail_roadtypes = ROADTYPES_ROAD; + return true; // TODO: should there be a proper check? } else { - Company *c = Company::GetIfValid(company); + const Company *c = Company::GetIfValid(company); if (c == nullptr) return false; - avail_roadtypes = (RoadTypes)c->avail_roadtypes | ROADTYPES_ROAD; // road is available for always for everybody + return HasBit(c->avail_roadtypes & ~_roadtypes_hidden_mask, roadtype); } - return (rts & ~avail_roadtypes) == 0; +} + +static RoadTypes GetMaskForRoadTramType(RoadTramType rtt) +{ + return rtt == RTT_TRAM ? _roadtypes_type : ~_roadtypes_type; +} + +/** + * Test if any buildable RoadType is available for a company. + * @param company the company in question + * @return true if company has any RoadTypes available + */ +bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt) +{ + return (Company::Get(company)->avail_roadtypes & ~_roadtypes_hidden_mask & GetMaskForRoadTramType(rtt)) != ROADTYPES_NONE; } /** * Validate functions for rail building. - * @param rt road type to check. + * @param roadtype road type to check. * @return true if the current company may build the road. */ -bool ValParamRoadType(const RoadType rt) +bool ValParamRoadType(RoadType roadtype) { - return HasRoadTypesAvail(_current_company, RoadTypeToRoadTypes(rt)); + return roadtype != INVALID_ROADTYPE && HasRoadTypeAvail(_current_company, roadtype); +} + +/** + * Add the road types that are to be introduced at the given date. + * @param rt Roadtype + * @param current The currently available roadtypes. + * @param date The date for the introduction comparisons. + * @return The road types that should be available when date + * introduced road types are taken into account as well. + */ +RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, Date date) +{ + RoadTypes rts = current; + + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + /* Unused road type. */ + if (rti->label == 0) continue; + + /* Not date introduced. */ + if (!IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue; + + /* Not yet introduced at this date. */ + if (rti->introduction_date > date) continue; + + /* Have we introduced all required roadtypes? */ + RoadTypes required = rti->introduction_required_roadtypes; + if ((rts & required) != required) continue; + + rts |= rti->introduces_roadtypes; + } + + /* When we added roadtypes we need to run this method again; the added + * roadtypes might enable more rail types to become introduced. */ + return rts == current ? rts : AddDateIntroducedRoadTypes(rts, date); } /** * Get the road types the given company can build. - * @param company the company to get the roadtypes for. + * @param company the company to get the road types for. + * @param introduces If true, include road types introduced by other road types * @return the road types. */ -RoadTypes GetCompanyRoadtypes(CompanyID company) +RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces) { - RoadTypes rt = ROADTYPES_NONE; + RoadTypes rts = ROADTYPES_NONE; - Engine *e; + const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { const EngineInfo *ei = &e->info; if (HasBit(ei->climates, _settings_game.game_creation.landscape) && (HasBit(e->company_avail, company) || _date >= e->intro_date + DAYS_IN_YEAR)) { - SetBit(rt, HasBit(ei->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + const RoadVehicleInfo *rvi = &e->u.road; + assert(rvi->roadtype < ROADTYPE_END); + if (introduces) { + rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes; + } else { + SetBit(rts, rvi->roadtype); + } + } + } + + if (introduces) return AddDateIntroducedRoadTypes(rts, _date); + return rts; +} + +/** + * Get list of road types, regardless of company availability. + * @param introduces If true, include road types introduced by other road types + * @return the road types. + */ +RoadTypes GetRoadTypes(bool introduces) +{ + RoadTypes rts = ROADTYPES_NONE; + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + const EngineInfo *ei = &e->info; + if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue; + + const RoadVehicleInfo *rvi = &e->u.road; + assert(rvi->roadtype < ROADTYPE_END); + if (introduces) { + rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes; + } else { + SetBit(rts, rvi->roadtype); } } - return rt; + if (introduces) return AddDateIntroducedRoadTypes(rts, MAX_DAY); + return rts; +} + +/** + * Get the road type for a given label. + * @param label the roadtype label. + * @param allow_alternate_labels Search in the alternate label lists as well. + * @return the roadtype. + */ +RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels) +{ + /* Loop through each road type until the label is found */ + for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(r); + if (rti->label == label) return r; + } + + if (allow_alternate_labels) { + /* Test if any road type defines the label as an alternate. */ + for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(r); + if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r; + } + } + + /* No matching label was found, so it is invalid */ + return INVALID_ROADTYPE; +} + +/** + * Returns the available RoadSubTypes for the provided RoadType + * If the given company is valid then will be returned a list of the available sub types at the current date, while passing + * a deity company will make all the sub types available + * @param rt the RoadType to filter + * @param c the company ID to check the roadtype against + * @param any_date whether to return only currently introduced roadtypes or also future ones + * @returns the existing RoadSubTypes + */ +RoadTypes ExistingRoadTypes(CompanyID c) +{ + /* Check only players which can actually own vehicles, editor and gamescripts are considered deities */ + if (c < OWNER_END) { + const Company *company = Company::GetIfValid(c); + if (company != nullptr) return company->avail_roadtypes; + } + + RoadTypes known_roadtypes = ROADTYPES_NONE; + + /* Find used roadtypes */ + Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + /* Check if the roadtype can be used in the current climate */ + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + + /* Check whether available for all potential companies */ + if (e->company_avail != (CompanyMask)-1) continue; + + known_roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes; + } + + /* Get the date introduced roadtypes as well. */ + known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, MAX_DAY); + + return known_roadtypes; +} + +/** + * Check whether we can build infrastructure for the given RoadType. This to disable building stations etc. when + * you are not allowed/able to have the RoadType yet. + * @param roadtype the roadtype to check this for + * @param company the company id to check this for + * @param any_date to check only existing vehicles or if it is possible to build them in the future + * @return true if there is any reason why you may build the infrastructure for the given roadtype + */ +bool CanBuildRoadTypeInfrastructure(RoadType roadtype, CompanyID company) +{ + if (_game_mode != GM_EDITOR && !Company::IsValidID(company)) return false; + if (!_settings_client.gui.disable_unsuitable_building) return true; + if (!HasAnyRoadTypesAvail(company, GetRoadTramType(roadtype))) return false; + + RoadTypes roadtypes = ExistingRoadTypes(company); + + /* Check if the filtered roadtypes does have the roadtype we are checking for + * and if we can build new ones */ + if (_settings_game.vehicle.max_roadveh > 0 && HasBit(roadtypes, roadtype)) { + /* Can we actually build the vehicle type? */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + if (!HasBit(e->company_avail, company)) continue; + if (HasPowerOnRoad(e->u.road.roadtype, roadtype) || HasPowerOnRoad(roadtype, e->u.road.roadtype)) return true; + } + return false; + } + + /* We should be able to build infrastructure when we have the actual vehicle type */ + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD && (company == OWNER_DEITY || v->owner == company) && + HasBit(roadtypes, RoadVehicle::From(v)->roadtype) && HasPowerOnRoad(RoadVehicle::From(v)->roadtype, roadtype)) return true; + } + + return false; } diff --git a/src/road.h b/src/road.h new file mode 100644 index 0000000000..c359fc779c --- /dev/null +++ b/src/road.h @@ -0,0 +1,316 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file road.h Road specific functions. */ + +#ifndef ROAD_H +#define ROAD_H + +#include "road_type.h" +#include "gfx_type.h" +#include "core/bitmath_func.hpp" +#include "strings_type.h" +#include "date_type.h" +#include "core/enum_type.hpp" +#include "newgrf.h" +#include "economy_func.h" + +#include + +enum RoadTramType : bool { + RTT_ROAD, + RTT_TRAM, +}; + +enum RoadTramTypes : uint8 { + RTTB_ROAD = 1 << RTT_ROAD, + RTTB_TRAM = 1 << RTT_TRAM, +}; +DECLARE_ENUM_AS_BIT_SET(RoadTramTypes) + +#define FOR_ALL_ROADTRAMTYPES(x) for (RoadTramType x : { RTT_ROAD, RTT_TRAM }) + +/** Roadtype flags. Starts with RO instead of R because R is used for rails */ +enum RoadTypeFlags { + ROTF_CATENARY = 0, ///< Bit number for adding catenary + ROTF_NO_LEVEL_CROSSING, ///< Bit number for disabling level crossing + ROTF_NO_HOUSES, ///< Bit number for setting this roadtype as not house friendly + ROTF_HIDDEN, ///< Bit number for hidden from construction. + ROTF_TOWN_BUILD, ///< Bit number for allowing towns to build this roadtype. + + ROTFB_NONE = 0, ///< All flags cleared. + ROTFB_CATENARY = 1 << ROTF_CATENARY, ///< Value for drawing a catenary. + ROTFB_NO_LEVEL_CROSSING = 1 << ROTF_NO_LEVEL_CROSSING, ///< Value for disabling a level crossing. + ROTFB_NO_HOUSES = 1 << ROTF_NO_HOUSES, ///< Value for for setting this roadtype as not house friendly. + ROTFB_HIDDEN = 1 << ROTF_HIDDEN, ///< Value for hidden from construction. + ROTFB_TOWN_BUILD = 1 << ROTF_TOWN_BUILD, ///< Value for allowing towns to build this roadtype. +}; +DECLARE_ENUM_AS_BIT_SET(RoadTypeFlags) + +struct SpriteGroup; + +/** Sprite groups for a roadtype. */ +enum RoadTypeSpriteGroup { + ROTSG_CURSORS, ///< Optional: Cursor and toolbar icon images + ROTSG_OVERLAY, ///< Optional: Images for overlaying track + ROTSG_GROUND, ///< Required: Main group of ground images + ROTSG_reserved1, ///< Placeholder, if we need specific tunnel sprites. + ROTSG_CATENARY_FRONT, ///< Optional: Catenary front + ROTSG_CATENARY_BACK, ///< Optional: Catenary back + ROTSG_BRIDGE, ///< Required: Bridge surface images + ROTSG_reserved2, ///< Placeholder, if we need specific level crossing sprites. + ROTSG_DEPOT, ///< Optional: Depot images + ROTSG_reserved3, ///< Placeholder, if we add road fences (for highways). + ROTSG_ROADSTOP, ///< Required: Drive-in stop surface + ROTSG_END, +}; + +/** List of road type labels. */ +typedef std::vector RoadTypeLabelList; + +class RoadTypeInfo { +public: + /** + * struct containing the sprites for the road GUI. @note only sprites referred to + * directly in the code are listed + */ + struct { + SpriteID build_x_road; ///< button for building single rail in X direction + SpriteID build_y_road; ///< button for building single rail in Y direction + SpriteID auto_road; ///< button for the autoroad construction + SpriteID build_depot; ///< button for building depots + SpriteID build_tunnel; ///< button for building a tunnel + SpriteID convert_road; ///< button for converting road types + } gui_sprites; + + struct { + CursorID road_swne; ///< Cursor for building rail in X direction + CursorID road_nwse; ///< Cursor for building rail in Y direction + CursorID autoroad; ///< Cursor for autorail tool + CursorID depot; ///< Cursor for building a depot + CursorID tunnel; ///< Cursor for building a tunnel + SpriteID convert_road; ///< Cursor for converting road types + } cursor; ///< Cursors associated with the road type. + + struct { + StringID name; ///< Name of this rail type. + StringID toolbar_caption; ///< Caption in the construction toolbar GUI for this rail type. + StringID menu_text; ///< Name of this rail type in the main toolbar dropdown. + StringID build_caption; ///< Caption of the build vehicle GUI for this rail type. + StringID replace_text; ///< Text used in the autoreplace GUI. + StringID new_engine; ///< Name of an engine for this type of road in the engine preview GUI. + + StringID err_build_road; ///< Building a normal piece of road + StringID err_remove_road; ///< Removing a normal piece of road + StringID err_depot; ///< Building a depot + StringID err_build_station[2]; ///< Building a bus or truck station + StringID err_remove_station[2]; ///< Removing of a bus or truck station + StringID err_convert_road; ///< Converting a road type + + StringID picker_title[2]; ///< Title for the station picker for bus or truck stations + StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations + } strings; ///< Strings associated with the rail type. + + /** bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power */ + RoadTypes powered_roadtypes; + + /** + * Bit mask of road type flags + */ + RoadTypeFlags flags; + + /** + * Cost multiplier for building this road type + */ + uint16 cost_multiplier; + + /** + * Cost multiplier for maintenance of this road type + */ + uint16 maintenance_multiplier; + + /** + * Maximum speed for vehicles travelling on this road type + */ + uint16 max_speed; + + /** + * Unique 32 bit road type identifier + */ + RoadTypeLabel label; + + /** + * Road type labels this type provides in addition to the main label. + */ + RoadTypeLabelList alternate_labels; + + /** + * Colour on mini-map + */ + byte map_colour; + + /** + * Introduction date. + * When #INVALID_DATE or a vehicle using this roadtype gets introduced earlier, + * the vehicle's introduction date will be used instead for this roadtype. + * The introduction at this date is furthermore limited by the + * #introduction_required_types. + */ + Date introduction_date; + + /** + * Bitmask of roadtypes that are required for this roadtype to be introduced + * at a given #introduction_date. + */ + RoadTypes introduction_required_roadtypes; + + /** + * Bitmask of which other roadtypes are introduced when this roadtype is introduced. + */ + RoadTypes introduces_roadtypes; + + /** + * The sorting order of this roadtype for the toolbar dropdown. + */ + byte sorting_order; + + /** + * NewGRF providing the Action3 for the roadtype. nullptr if not available. + */ + const GRFFile *grffile[ROTSG_END]; + + /** + * Sprite groups for resolving sprites + */ + const SpriteGroup *group[ROTSG_END]; + + inline bool UsesOverlay() const + { + return this->group[ROTSG_GROUND] != nullptr; + } +}; + +extern RoadTypes _roadtypes_type; + +static inline bool RoadTypeIsRoad(RoadType roadtype) +{ + return !HasBit(_roadtypes_type, roadtype); +} + +static inline bool RoadTypeIsTram(RoadType roadtype) +{ + return HasBit(_roadtypes_type, roadtype); +} + +static inline RoadTramType GetRoadTramType(RoadType roadtype) +{ + return RoadTypeIsTram(roadtype) ? RTT_TRAM : RTT_ROAD; +} + +static inline RoadTramType OtherRoadTramType(RoadTramType rtt) +{ + return rtt == RTT_ROAD ? RTT_TRAM : RTT_ROAD; +} + +/** + * Returns a pointer to the Roadtype information for a given roadtype + * @param roadtype the road type which the information is requested for + * @return The pointer to the RoadTypeInfo + */ +static inline const RoadTypeInfo *GetRoadTypeInfo(RoadType roadtype) +{ + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + assert(roadtype < ROADTYPE_END); + return &_roadtypes[roadtype]; +} + +/** + * Checks if an engine of the given RoadType got power on a tile with a given + * RoadType. This would normally just be an equality check, but for electrified + * roads (which also support non-electric vehicles). + * @return Whether the engine got power on this tile. + * @param enginetype The RoadType of the engine we are considering. + * @param tiletype The RoadType of the tile we are considering. + */ +static inline bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype) +{ + return HasBit(GetRoadTypeInfo(enginetype)->powered_roadtypes, tiletype); +} + +/** + * Returns the cost of building the specified roadtype. + * @param roadtype The roadtype being built. + * @return The cost multiplier. + */ +static inline Money RoadBuildCost(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + return (_price[PR_BUILD_ROAD] * GetRoadTypeInfo(roadtype)->cost_multiplier) >> 3; +} + +/** + * Returns the cost of clearing the specified roadtype. + * @param roadtype The roadtype being removed. + * @return The cost. + */ +static inline Money RoadClearCost(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + + /* Flat fee for removing road. */ + if (RoadTypeIsRoad(roadtype)) return _price[PR_CLEAR_ROAD]; + + /* Clearing tram earns a little money, but also incurs the standard clear road cost, + * so no profit can be made. */ + return _price[PR_CLEAR_ROAD] - RoadBuildCost(roadtype) * 3 / 4; +} + +/** + * Calculates the cost of road conversion + * @param from The roadtype we are converting from + * @param to The roadtype we are converting to + * @return Cost per RoadBit + */ +static inline Money RoadConvertCost(RoadType from, RoadType to) +{ + /* Don't apply convert costs when converting to the same roadtype (ex. building a roadstop over existing road) */ + if (from == to) return (Money)0; + + /* Same cost as removing and then building. */ + return RoadBuildCost(to) + RoadClearCost(from); +} + +/** + * Test if road disallows level crossings + * @param roadtype The roadtype we are testing + * @return True iff the roadtype disallows level crossings + */ +static inline bool RoadNoLevelCrossing(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + return HasBit(GetRoadTypeInfo(roadtype)->flags, ROTF_NO_LEVEL_CROSSING); +} + +RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels = true); + +void ResetRoadTypes(); +void InitRoadTypes(); +RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt); +bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt); + +extern std::vector _sorted_roadtypes; +extern RoadTypes _roadtypes_hidden_mask; + +/** + * Loop header for iterating over roadtypes, sorted by sortorder. + * @param var Roadtype. + */ +#define FOR_ALL_SORTED_ROADTYPES(var) for (uint8 index = 0; index < _sorted_roadtypes.size() && (var = _sorted_roadtypes[index], true) ; index++) + +#endif /* ROAD_H */ diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index b7f422c77a..2ba8707433 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -11,6 +11,7 @@ #include "stdafx.h" #include "cmd_helper.h" +#include "road.h" #include "road_internal.h" #include "viewport_func.h" #include "command_func.h" @@ -31,15 +32,152 @@ #include "town.h" #include "company_base.h" #include "core/random_func.hpp" +#include "newgrf_debug.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "date_func.h" #include "genworld.h" #include "company_gui.h" +#include "road_func.h" #include "table/strings.h" +#include "table/roadtypes.h" #include "safeguards.h" +/** Helper type for lists/vectors of road vehicles */ +typedef std::vector RoadVehicleList; + +RoadTypeInfo _roadtypes[ROADTYPE_END]; +std::vector _sorted_roadtypes; +RoadTypes _roadtypes_hidden_mask; + +/** + * Bitmap of road/tram types. + * Bit if set if a roadtype is tram. + */ +RoadTypes _roadtypes_type; + +/** + * Reset all road type information to its default values. + */ +void ResetRoadTypes() +{ + assert_compile(lengthof(_original_roadtypes) <= lengthof(_roadtypes)); + + uint i = 0; + for (; i < lengthof(_original_roadtypes); i++) _roadtypes[i] = _original_roadtypes[i]; + + static const RoadTypeInfo empty_roadtype = { + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, 0, {}, {} }, + ROADTYPES_NONE, ROTFB_NONE, 0, 0, 0, 0, + RoadTypeLabelList(), 0, 0, ROADTYPES_NONE, ROADTYPES_NONE, 0, + {}, {} }; + for (; i < lengthof(_roadtypes); i++) _roadtypes[i] = empty_roadtype; + + _roadtypes_hidden_mask = ROADTYPES_NONE; + _roadtypes_type = ROADTYPES_TRAM; +} + +void ResolveRoadTypeGUISprites(RoadTypeInfo *rti) +{ + SpriteID cursors_base = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_CURSORS); + if (cursors_base != 0) { + rti->gui_sprites.build_x_road = cursors_base + 0; + rti->gui_sprites.build_y_road = cursors_base + 1; + rti->gui_sprites.auto_road = cursors_base + 2; + rti->gui_sprites.build_depot = cursors_base + 3; + rti->gui_sprites.build_tunnel = cursors_base + 4; + rti->gui_sprites.convert_road = cursors_base + 5; + rti->cursor.road_swne = cursors_base + 6; + rti->cursor.road_nwse = cursors_base + 7; + rti->cursor.autoroad = cursors_base + 8; + rti->cursor.depot = cursors_base + 9; + rti->cursor.tunnel = cursors_base + 10; + rti->cursor.convert_road = cursors_base + 11; + } +} + +/** + * Compare roadtypes based on their sorting order. + * @param first The roadtype to compare to. + * @param second The roadtype to compare. + * @return True iff the first should be sorted before the second. + */ +static bool CompareRoadTypes(const RoadType &first, const RoadType &second) +{ + if (RoadTypeIsRoad(first) == RoadTypeIsRoad(second)) { + return GetRoadTypeInfo(first)->sorting_order < GetRoadTypeInfo(second)->sorting_order; + } + return RoadTypeIsTram(first) < RoadTypeIsTram(second); +} + +/** + * Resolve sprites of custom road types + */ +void InitRoadTypes() +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + RoadTypeInfo *rti = &_roadtypes[rt]; + ResolveRoadTypeGUISprites(rti); + if (HasBit(rti->flags, ROTF_HIDDEN)) SetBit(_roadtypes_hidden_mask, rt); + } + + _sorted_roadtypes.clear(); + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (_roadtypes[rt].label != 0 && !HasBit(_roadtypes_hidden_mask, rt)) { + _sorted_roadtypes.push_back(rt); + } + } + std::sort(_sorted_roadtypes.begin(), _sorted_roadtypes.end(), CompareRoadTypes); +} + +/** + * Allocate a new road type label + */ +RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt) +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + RoadTypeInfo *rti = &_roadtypes[rt]; + + if (rti->label == 0) { + /* Set up new road type */ + *rti = _original_roadtypes[(rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD]; + rti->label = label; + rti->alternate_labels.clear(); + rti->flags = ROTFB_NONE; + rti->introduction_date = INVALID_DATE; + + /* Make us compatible with ourself. */ + rti->powered_roadtypes = (RoadTypes)(1ULL << rt); + + /* We also introduce ourself. */ + rti->introduces_roadtypes = (RoadTypes)(1ULL << rt); + + /* Default sort order; order of allocation, but with some + * offsets so it's easier for NewGRF to pick a spot without + * changing the order of other (original) road types. + * The << is so you can place other roadtypes in between the + * other roadtypes, the 7 is to be able to place something + * before the first (default) road type. */ + rti->sorting_order = rt << 2 | 7; + + /* Set bitmap of road/tram types */ + if (rtt == RTT_TRAM) { + SetBit(_roadtypes_type, rt); + } else { + ClrBit(_roadtypes_type, rt); + } + + return rt; + } + } + + return INVALID_ROADTYPE; +} + /** * Verify whether a road vehicle is available. * @return \c true if at least one road vehicle is available, \c false if not @@ -52,6 +190,23 @@ bool RoadVehiclesAreBuilt() return false; } +/** + * Update road infrastructure counts for a company. + * @param rt Road type to update count of. + * @param o Owner of road piece. + * @param count Number of road pieces to adjust. + */ +void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count) +{ + if (rt == INVALID_ROADTYPE) return; + + Company *c = Company::GetIfValid(o); + if (c == nullptr) return; + + c->infrastructure.road[rt] += count; + DirtyCompanyInfrastructureWindows(c->index); +} + /** Invalid RoadBits on slopes. */ extern const RoadBits _invalid_tileh_slopes_road[2][15] = { /* The inverse of the mixable RoadBits on a leveled slope */ @@ -103,22 +258,22 @@ extern const RoadBits _invalid_tileh_slopes_road[2][15] = { static Foundation GetRoadFoundation(Slope tileh, RoadBits bits); -void NotifyRoadLayoutChangedIfTileNonLeaf(TileIndex tile, RoadType rt, RoadBits present_bits) +void NotifyRoadLayoutChangedIfTileNonLeaf(TileIndex tile, RoadTramType rtt, RoadBits present_bits) { uint connections = 0; - if ((present_bits & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW)) connections++; - if ((present_bits & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW)) connections++; - if ((present_bits & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE)) connections++; - if ((present_bits & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE)) connections++; + if ((present_bits & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rtt) & ROAD_SW)) connections++; + if ((present_bits & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rtt) & ROAD_NW)) connections++; + if ((present_bits & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rtt) & ROAD_NE)) connections++; + if ((present_bits & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rtt) & ROAD_SE)) connections++; if (connections >= 2) { NotifyRoadLayoutChanged(); } } -void NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(TileIndex start, TileIndex end, DiagDirection start_dir, RoadType rt) +void NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(TileIndex start, TileIndex end, DiagDirection start_dir, RoadTramType rtt) { - if (!(GetAnyRoadBits(TileAddByDiagDir(start, ReverseDiagDir(start_dir)), rt) & DiagDirToRoadBits(start_dir))) return; - if (!(GetAnyRoadBits(TileAddByDiagDir(end, start_dir), rt) & DiagDirToRoadBits(ReverseDiagDir(start_dir)))) return; + if (!(GetAnyRoadBits(TileAddByDiagDir(start, ReverseDiagDir(start_dir)), rtt) & DiagDirToRoadBits(start_dir))) return; + if (!(GetAnyRoadBits(TileAddByDiagDir(end, start_dir), rtt) & DiagDirToRoadBits(ReverseDiagDir(start_dir)))) return; NotifyRoadLayoutChanged(); } @@ -133,7 +288,7 @@ void NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(TileIndex start, TileInd * @param town_check Shall the town rating checked/affected * @return A succeeded command when it is allowed to remove the road bits, a failed command otherwise. */ -CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check) +CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadTramType rtt, DoCommandFlag flags, bool town_check) { if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return CommandCost(); @@ -141,7 +296,7 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R * Towns are not be allowed to remove non "normal" road pieces, like tram * tracks as that would result in trams that cannot turn. */ if (_current_company == OWNER_WATER || - (rt == ROADTYPE_ROAD && !Company::IsValidID(_current_company))) return CommandCost(); + (rtt == RTT_ROAD && !Company::IsValidID(_current_company))) return CommandCost(); /* Only do the special processing if the road is owned * by a town */ @@ -165,11 +320,11 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R /* Get a bitmask of which neighbouring roads has a tile */ RoadBits n = ROAD_NONE; - RoadBits present = GetAnyRoadBits(tile, rt); - if ((present & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW)) n |= ROAD_NE; - if ((present & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW)) n |= ROAD_SE; - if ((present & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE)) n |= ROAD_SW; - if ((present & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE)) n |= ROAD_NW; + RoadBits present = GetAnyRoadBits(tile, rtt); + if ((present & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rtt) & ROAD_SW)) n |= ROAD_NE; + if ((present & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rtt) & ROAD_NW)) n |= ROAD_SE; + if ((present & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rtt) & ROAD_NE)) n |= ROAD_SW; + if ((present & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rtt) & ROAD_SE)) n |= ROAD_NW; int rating_decrease = RATING_ROAD_DOWN_STEP_EDGE; /* If 0 or 1 bits are set in n, or if no bits that match the bits to remove, @@ -197,11 +352,13 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R * @param crossing_check should we check if there is a tram track when we are removing road from crossing? * @param town_check should we check if the town allows removal? */ -static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true) +static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadTramType rtt, bool crossing_check, bool town_check = true) { - RoadTypes rts = GetRoadTypes(tile); + assert(pieces != ROAD_NONE); + + RoadType existing_rt = MayHaveRoad(tile) ? GetRoadType(tile, rtt) : INVALID_ROADTYPE; /* The tile doesn't have the given road type */ - if (!HasBit(rts, rt)) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if (existing_rt == INVALID_ROADTYPE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); switch (GetTileType(tile)) { case MP_ROAD: { @@ -229,7 +386,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec return CMD_ERROR; } - CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rt), rt, flags, town_check); + CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rtt), rtt, flags, town_check); if (ret.Failed()) return ret; if (!IsTileType(tile, MP_ROAD)) { @@ -238,14 +395,13 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec (_settings_game.construction.road_custom_bridge_heads || IsRoadCustomBridgeHead(tile)); /* If it's the last roadtype, just clear the whole tile */ - if (!custom_bridge_head && rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + if (!custom_bridge_head && GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); CommandCost cost(EXPENSES_CONSTRUCTION); if (IsTileType(tile, MP_TUNNELBRIDGE)) { const RoadBits entrance_piece = DiagDirToRoadBits(GetTunnelBridgeDirection(tile)); const RoadBits axial_pieces = AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))); - const RoadBits existing = IsBridge(tile) ? GetCustomBridgeHeadRoadBits(tile, rt) : axial_pieces; - const RoadType other_rt = (rt == ROADTYPE_ROAD) ? ROADTYPE_TRAM : ROADTYPE_ROAD; + const RoadBits existing = IsBridge(tile) ? GetCustomBridgeHeadRoadBits(tile, rtt) : axial_pieces; /* handle case where we would otherwise leave a single bridge entrance piece */ if ((existing & ~pieces) == entrance_piece) { @@ -253,7 +409,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } /* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */ - if ((existing & pieces) == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if ((existing & pieces) == ROAD_NONE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); if (!custom_bridge_head) pieces |= axial_pieces; @@ -261,7 +417,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec const uint middle_len = GetTunnelBridgeLength(other_end, tile); uint pieces_count = 0; - const RoadBits other_end_existing = IsBridge(other_end) ? GetCustomBridgeHeadRoadBits(other_end, rt) : axial_pieces; + const RoadBits other_end_existing = IsBridge(other_end) ? GetCustomBridgeHeadRoadBits(other_end, rtt) : axial_pieces; RoadBits other_end_pieces = ROAD_NONE; if (pieces & entrance_piece) { other_end_pieces |= MirrorRoadBits(entrance_piece); @@ -270,7 +426,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec other_end_pieces |= other_end_existing; } pieces_count += middle_len * 2; - if (custom_bridge_head && ((GetCustomBridgeHeadRoadBits(tile, other_rt) & entrance_piece) == ROAD_NONE)) { + if (custom_bridge_head && ((GetCustomBridgeHeadRoadBits(tile, OtherRoadTramType(rtt)) & entrance_piece) == ROAD_NONE)) { /* can't leave no entrance pieces for any road type */ return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } @@ -278,26 +434,26 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec pieces_count += CountBits(pieces & existing); pieces_count += CountBits(other_end_pieces & other_end_existing); - cost.AddCost(pieces_count * _price[PR_CLEAR_ROAD]); + cost.AddCost(pieces_count * RoadClearCost(existing_rt)); if (flags & DC_EXEC) { SubtractRoadTunnelBridgeInfrastructure(tile, other_end); const RoadBits bits = existing & ~pieces; const RoadBits other_bits = other_end_existing & ~other_end_pieces; - if (bits == ROAD_NONE) SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); - if (other_bits == ROAD_NONE) SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt)); + if (bits == ROAD_NONE) SetRoadType(tile, rtt, INVALID_ROADTYPE); + if (other_bits == ROAD_NONE) SetRoadType(other_end, rtt, INVALID_ROADTYPE); if (IsBridge(tile)) { - SetCustomBridgeHeadRoadBits(tile, rt, bits); - SetCustomBridgeHeadRoadBits(other_end, rt, other_bits); + SetCustomBridgeHeadRoadBits(tile, rtt, bits); + SetCustomBridgeHeadRoadBits(other_end, rtt, other_bits); } if (bits == ROAD_NONE && other_bits == ROAD_NONE) { /* If the owner of the bridge sells all its road, also move the ownership * to the owner of the other roadtype, unless the bridge owner is a town. */ - Owner other_owner = GetRoadOwner(tile, other_rt); + Owner other_owner = GetRoadOwner(tile, OtherRoadTramType(rtt)); if (!IsTileOwner(tile, other_owner) && !IsTileOwner(tile, OWNER_TOWN)) { SetTileOwner(tile, other_owner); SetTileOwner(other_end, other_owner); @@ -320,15 +476,11 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } } else { assert_tile(IsDriveThroughStopTile(tile), tile); - cost.AddCost(_price[PR_CLEAR_ROAD] * 2); + cost.AddCost(RoadClearCost(existing_rt) * 2); if (flags & DC_EXEC) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } - SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2); + SetRoadType(tile, rtt, INVALID_ROADTYPE); MarkTileDirtyByTile(tile); NotifyRoadLayoutChanged(); } @@ -345,8 +497,8 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)); } - RoadBits present = GetRoadBits(tile, rt); - const RoadBits other = GetOtherRoadBits(tile, rt); + RoadBits present = GetRoadBits(tile, rtt); + const RoadBits other = GetRoadBits(tile, OtherRoadTramType(rtt)); const Foundation f = GetRoadFoundation(tileh, present); if (HasRoadWorks(tile) && _current_company != OWNER_WATER) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); @@ -361,7 +513,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec /* limit the bits to delete to the existing bits. */ pieces &= present; - if (pieces == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if (pieces == ROAD_NONE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); /* Now set present what it will be after the remove */ present ^= pieces; @@ -384,40 +536,35 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } } - NotifyRoadLayoutChangedIfTileNonLeaf(tile, rt, present | pieces); - - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - c->infrastructure.road[rt] -= CountBits(pieces); - DirtyCompanyInfrastructureWindows(c->index); - } + NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, present | pieces); + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -(int)CountBits(pieces)); if (present == ROAD_NONE) { - RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); - if (rts == ROADTYPES_NONE) { + /* No other road type, just clear tile. */ + if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) { /* Includes MarkTileDirtyByTile() */ DoClearSquare(tile); } else { - if (rt == ROADTYPE_ROAD && IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) { + if (rtt == RTT_ROAD && IsRoadOwner(tile, rtt, OWNER_TOWN)) { /* Update nearest-town index */ const Town *town = CalcClosestTownFromTile(tile); SetTownIndex(tile, town == nullptr ? INVALID_TOWN : town->index); } - SetRoadBits(tile, ROAD_NONE, rt); - SetRoadTypes(tile, rts); + SetRoadBits(tile, ROAD_NONE, rtt); + SetRoadType(tile, rtt, INVALID_ROADTYPE); MarkTileDirtyByTile(tile); } } else { /* When bits are removed, you *always* end up with something that * is not a complete straight road tile. However, trams do not have * onewayness, so they cannot remove it either. */ - if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE); - SetRoadBits(tile, present, rt); + if (rtt == RTT_ROAD) SetDisallowedRoadDirections(tile, DRD_NONE); + SetRoadBits(tile, present, rtt); MarkTileDirtyByTile(tile); } } - CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * _price[PR_CLEAR_ROAD]); + CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * RoadClearCost(existing_rt)); /* If we build a foundation we have to pay for it. */ if (f == FOUNDATION_NONE && GetRoadFoundation(tileh, present) != FOUNDATION_NONE) cost.AddCost(_price[PR_BUILD_FOUNDATION]); @@ -429,22 +576,13 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec return CMD_ERROR; } - /* Don't allow road to be removed from the crossing when there is tram; - * we can't draw the crossing without roadbits ;) */ - if (rt == ROADTYPE_ROAD && HasTileRoadType(tile, ROADTYPE_TRAM) && (flags & DC_EXEC || crossing_check)) return CMD_ERROR; - if (flags & DC_EXEC) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2); Track railtrack = GetCrossingRailTrack(tile); - RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); - NotifyRoadLayoutChangedIfTileNonLeaf(tile, rt, GetCrossingRoadBits(tile)); - if (rts == ROADTYPES_NONE) { + NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, GetCrossingRoadBits(tile)); + if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) { TrackBits tracks = GetCrossingRailBits(tile); bool reserved = HasCrossingReservation(tile); MakeRailNormal(tile, GetTileOwner(tile), tracks, GetRailType(tile)); @@ -452,18 +590,18 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec /* Update rail count for level crossings. The plain track should still be accounted * for, so only subtract the difference to the level crossing cost. */ - c = Company::GetIfValid(GetTileOwner(tile)); + Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != nullptr) { c->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); } } else { - SetRoadTypes(tile, rts); + SetRoadType(tile, rtt, INVALID_ROADTYPE); } MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, railtrack); } - return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROAD] * 2); + return CommandCost(EXPENSES_CONSTRUCTION, RoadClearCost(existing_rt) * 2); } default: @@ -544,9 +682,9 @@ static CommandCost CheckRoadSlope(Slope tileh, RoadBits *pieces, RoadBits existi * @param tile tile where to build road * @param flags operation to perform * @param p1 bit 0..3 road pieces to build (RoadBits) - * bit 4..5 road type - * bit 6..7 disallowed directions to toggle - * bit 8 disable custom bridge heads + * bit 4..9 road type + * bit 11..12 disallowed directions to toggle + * bit 13 disable custom bridge heads * @param p2 the town that is building the road (0 if not applicable) * @param text unused * @return the cost of this operation or an error @@ -581,14 +719,15 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* do not allow building 'zero' road bits, code wouldn't handle it */ if (pieces == ROAD_NONE) return CMD_ERROR; - RoadType rt = Extract(p1); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p1); + if (!ValParamRoadType(rt)) return CMD_ERROR; - DisallowedRoadDirections toggle_drd = Extract(p1); + DisallowedRoadDirections toggle_drd = Extract(p1); - bool disable_custom_bridge_heads = HasBit(p1, 8); + bool disable_custom_bridge_heads = HasBit(p1, 13); Slope tileh = GetTileSlope(tile); + RoadTramType rtt = GetRoadTramType(rt); bool need_to_clear = false; switch (GetTileType(tile)) { @@ -597,21 +736,21 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 case ROAD_TILE_NORMAL: { if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); - other_bits = GetOtherRoadBits(tile, rt); - if (!HasTileRoadType(tile, rt)) break; + other_bits = GetRoadBits(tile, OtherRoadTramType(rtt)); + if (!HasTileRoadType(tile, rtt)) break; - existing = GetRoadBits(tile, rt); + existing = GetRoadBits(tile, rtt); bool crossing = !IsStraightRoad(existing | pieces); - if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { + if (rtt == RTT_ROAD && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { /* Junctions cannot be one-way */ return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); } if ((existing & pieces) == pieces) { /* We only want to set the (dis)allowed road directions */ - if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM) { + if (toggle_drd != DRD_NONE && rtt == RTT_ROAD) { if (crossing) return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); - Owner owner = GetRoadOwner(tile, ROADTYPE_ROAD); + Owner owner = GetRoadOwner(tile, rtt); if (owner != OWNER_NONE) { CommandCost ret = CheckOwnership(owner, tile); if (ret.Failed()) return ret; @@ -630,7 +769,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* Ignore half built tiles */ - if ((flags & DC_EXEC) && rt != ROADTYPE_TRAM && IsStraightRoad(existing)) { + if ((flags & DC_EXEC) && IsStraightRoad(existing)) { SetDisallowedRoadDirections(tile, dis_new); MarkTileDirtyByTile(tile); } @@ -640,8 +779,8 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ - if (rt == ROADTYPE_TRAM && HasExactlyOneBit(existing)) { - Owner owner = GetRoadOwner(tile, rt); + if (rtt == RTT_TRAM && HasExactlyOneBit(existing)) { + Owner owner = GetRoadOwner(tile, rtt); if (Company::IsValidID(owner)) { CommandCost ret = CheckOwnership(owner); if (ret.Failed()) return ret; @@ -651,15 +790,19 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } case ROAD_TILE_CROSSING: + if (RoadNoLevelCrossing(rt)) { + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + } + other_bits = GetCrossingRoadBits(tile); if (pieces & ComplementRoadBits(other_bits)) goto do_clear; pieces = other_bits; // we need to pay for both roadbits - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; case ROAD_TILE_DEPOT: - if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); goto do_clear; default: NOT_REACHED(); @@ -678,8 +821,12 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear; + if (RoadNoLevelCrossing(rt)) { + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + } + if (RailNoLevelCrossings(GetRailType(tile))) { - return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_RAIL); } Axis roaddir; @@ -704,15 +851,11 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Track railtrack = AxisToTrack(OtherAxis(roaddir)); YapfNotifyTrackLayoutChange(tile, railtrack); /* Update company infrastructure counts. A level crossing has two road bits. */ - Company *c = Company::GetIfValid(company); - if (c != nullptr) { - c->infrastructure.road[rt] += 2; - if (rt != ROADTYPE_ROAD) c->infrastructure.road[ROADTYPE_ROAD] += 2; - DirtyCompanyInfrastructureWindows(company); - } + UpdateCompanyRoadInfrastructure(rt, company, 2); + /* Update rail count for level crossings. The plain track is already * counted, so only add the difference to the level crossing cost. */ - c = Company::GetIfValid(GetTileOwner(tile)); + Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != nullptr) { c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); @@ -720,24 +863,24 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Always add road to the roadtypes (can't draw without it) */ bool reserved = HasBit(GetRailReservationTrackBits(tile), railtrack); - MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt) | ROADTYPES_ROAD, p2); + MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), rtt == RTT_ROAD ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2); SetCrossingReservation(tile, reserved); UpdateLevelCrossing(tile, false); - NotifyRoadLayoutChangedIfTileNonLeaf(tile, rt, GetCrossingRoadBits(tile)); + NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, GetCrossingRoadBits(tile)); MarkTileDirtyByTile(tile); } - return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_ROAD] * (rt == ROADTYPE_ROAD ? 2 : 4)); + return CommandCost(EXPENSES_CONSTRUCTION, 2 * RoadBuildCost(rt)); } case MP_STATION: { - if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); if (!IsDriveThroughStopTile(tile)) goto do_clear; RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile))); if (pieces & ~curbits) goto do_clear; pieces = curbits; // we need to pay for both roadbits - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; } @@ -750,7 +893,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 const DiagDirection entrance_dir = GetTunnelBridgeDirection(tile); const RoadBits entrance_piece = DiagDirToRoadBits(entrance_dir); const RoadBits axial_pieces = AxisToRoadBits(DiagDirToAxis(entrance_dir)); - existing = GetCustomBridgeHeadRoadBits(tile, rt); + existing = GetCustomBridgeHeadRoadBits(tile, rtt); if (!(_settings_game.construction.road_custom_bridge_heads && HasBridgeFlatRamp(tileh, DiagDirToAxis(entrance_dir))) || disable_custom_bridge_heads) { /* Ordinary bridge heads only */ @@ -794,7 +937,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 other_end_added_pieces = MirrorRoadBits(entrance_piece); added_pieces_count += 1 + (GetTunnelBridgeLength(tile, other_end) * 2); - other_end_existing = GetCustomBridgeHeadRoadBits(other_end, rt); + other_end_existing = GetCustomBridgeHeadRoadBits(other_end, rtt); assert((other_end_added_pieces & other_end_existing) == ROAD_NONE); if (other_end_existing == ROAD_NONE) { @@ -807,18 +950,22 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } } - cost.AddCost(added_pieces_count * _price[PR_BUILD_ROAD]); + cost.AddCost(added_pieces_count * RoadBuildCost(rt)); if (flags & DC_EXEC) { SubtractRoadTunnelBridgeInfrastructure(tile, other_end); - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - if (!existing) SetRoadOwner(tile, rt, company); - SetCustomBridgeHeadRoadBits(tile, rt, existing | pieces); + if (!existing) { + SetRoadType(tile, rtt, rt); + SetRoadOwner(tile, rtt, company); + } + SetCustomBridgeHeadRoadBits(tile, rtt, existing | pieces); if (other_end_added_pieces) { - SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt)); - if (!other_end_existing) SetRoadOwner(other_end, rt, company); - SetCustomBridgeHeadRoadBits(other_end, rt, other_end_existing | other_end_added_pieces); + if (!other_end_existing) { + SetRoadType(other_end, rtt, rt); + SetRoadOwner(other_end, rtt, company); + } + SetCustomBridgeHeadRoadBits(other_end, rtt, other_end_existing | other_end_added_pieces); } MarkBridgeDirty(tile); @@ -832,7 +979,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } else { // IsTunnel(tile) /* Only allow building the outer roadbit, so building long roads stops at existing bridges */ if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) goto do_clear; - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); /* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */ CommandCost ret = TunnelBridgeIsFree(tile, other_end); if (ret.Failed()) return ret; @@ -874,15 +1021,10 @@ do_clear:; Slope slope = GetTileSlope(tile); Foundation found_new = GetRoadFoundation(slope, pieces | existing); - /* Test if all other roadtypes can be built at that foundation */ - for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) { - if (rtest != rt) { // check only other road types - RoadBits bits = GetRoadBits(tile, rtest); - /* do not check if there are not road bits of given type */ - if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) { - return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); - } - } + RoadBits bits = GetRoadBits(tile, OtherRoadTramType(rtt)); + /* do not check if there are not road bits of given type */ + if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) { + return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } } } @@ -890,6 +1032,23 @@ do_clear:; CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; + if (IsNormalRoadTile(tile)) { + /* If the road types don't match, try to convert only if vehicles of + * the new road type are not powered on the present road type and vehicles of + * the present road type are powered on the new road type. */ + RoadType existing_rt = GetRoadType(tile, rtt); + if (existing_rt != INVALID_ROADTYPE && existing_rt != rt) { + if (HasPowerOnRoad(rt, existing_rt)) { + rt = existing_rt; + } else if (HasPowerOnRoad(existing_rt, rt)) { + CommandCost ret = DoCommand(tile, tile, rt, flags, CMD_CONVERT_ROAD); + if (ret.Failed()) return ret; + cost.AddCost(ret); + } else { + return CMD_ERROR; + } + } + } } uint num_pieces = (!need_to_clear && IsTileType(tile, MP_TUNNELBRIDGE)) ? @@ -898,29 +1057,29 @@ do_clear:; /* Count pieces */ CountBits(pieces); - cost.AddCost(num_pieces * _price[PR_BUILD_ROAD]); + cost.AddCost(num_pieces * RoadBuildCost(rt)); if (flags & DC_EXEC) { switch (GetTileType(tile)) { case MP_ROAD: { - RoadTileType rtt = GetRoadTileType(tile); - if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) { - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(tile, rt, company); - if (rt == ROADTYPE_ROAD) SetTownIndex(tile, p2); + RoadTileType rttype = GetRoadTileType(tile); + if (existing == ROAD_NONE || rttype == ROAD_TILE_CROSSING) { + SetRoadType(tile, rtt, rt); + SetRoadOwner(tile, rtt, company); + if (rtt == RTT_ROAD) SetTownIndex(tile, p2); } - if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt); - NotifyRoadLayoutChangedIfTileNonLeaf(tile, rt, existing | pieces); + if (rttype != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rtt); + NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, existing | pieces); break; } case MP_TUNNELBRIDGE: { TileIndex other_end = GetOtherTunnelBridgeEnd(tile); - SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt)); - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(other_end, rt, company); - SetRoadOwner(tile, rt, company); + SetRoadType(other_end, rtt, rt); + SetRoadType(tile, rtt, rt); + SetRoadOwner(other_end, rtt, company); + SetRoadOwner(tile, rtt, company); /* Mark tiles dirty that have been repaved */ if (IsBridge(tile)) { @@ -933,28 +1092,25 @@ do_clear:; break; } - case MP_STATION: + case MP_STATION: { assert_tile(IsDriveThroughStopTile(tile), tile); - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(tile, rt, company); + SetRoadType(tile, rtt, rt); + SetRoadOwner(tile, rtt, company); NotifyRoadLayoutChanged(); break; + } default: - MakeRoadNormal(tile, pieces, RoadTypeToRoadTypes(rt), p2, company, company); - NotifyRoadLayoutChangedIfTileNonLeaf(tile, rt, pieces); + MakeRoadNormal(tile, pieces, (rtt == RTT_ROAD) ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2, company, company); + NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, pieces); break; } /* Update company infrastructure count. */ - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - if (IsTileType(tile, MP_TUNNELBRIDGE)) num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR; - c->infrastructure.road[rt] += num_pieces; - DirtyCompanyInfrastructureWindows(c->index); - } + if (IsTileType(tile, MP_TUNNELBRIDGE)) num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR; + UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), num_pieces); - if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) { + if (rtt == RTT_ROAD && IsNormalRoadTile(tile)) { existing |= pieces; SetDisallowedRoadDirections(tile, IsStraightRoad(existing) ? GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE); @@ -975,8 +1131,14 @@ do_clear:; static bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir) { tile += TileOffsByDiagDir(dir); - if (!IsValidTile(tile)) return false; - RoadBits bits = GetAnyRoadBits(tile, rt, false); + if (!IsValidTile(tile) || !MayHaveRoad(tile)) return false; + + RoadTramType rtt = GetRoadTramType(rt); + RoadType existing = GetRoadType(tile, rtt); + if (existing == INVALID_ROADTYPE) return false; + if (!HasPowerOnRoad(existing, rt) && !HasPowerOnRoad(rt, existing)) return false; + + RoadBits bits = GetAnyRoadBits(tile, rtt, false); return (bits & DiagDirToRoadBits(ReverseDiagDir(dir))) != 0; } @@ -989,9 +1151,9 @@ static bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir) * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) - * - p2 = (bit 3 + 4) - road type - * - p2 = (bit 5) - set road direction - * - p2 = (bit 6) - defines two different behaviors for this command: + * - p2 = (bit 3..8) - road type + * - p2 = (bit 10) - set road direction + * - p2 = (bit 11) - defines two different behaviors for this command: * - 0 = Build up to an obstacle. Do not build the first and last roadbits unless they can be connected to something, or if we are building a single tile * - 1 = Fail if an obstacle is found. Always take into account bit 0 and 1. Disable custom bridge heads. This behavior is used for scripts * @param text unused @@ -1002,10 +1164,10 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p DisallowedRoadDirections drd = DRD_NORTHBOUND; if (p1 >= MapSize()) return CMD_ERROR; - TileIndex end_tile = p1; - RoadType rt = Extract(p2); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ @@ -1026,13 +1188,13 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p * when you just 'click' on one tile to build them. */ if ((axis == AXIS_Y) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH; /* No disallowed direction bits have to be toggled */ - if (!HasBit(p2, 5)) drd = DRD_NONE; + if (!HasBit(p2, 10)) drd = DRD_NONE; CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost last_error = CMD_ERROR; TileIndex tile = start_tile; bool had_success = false; - bool is_ai = HasBit(p2, 6); + bool is_ai = HasBit(p2, 11); /* Start tile is the first tile clicked by the user. */ for (;;) { @@ -1052,7 +1214,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p if (tile == start_tile && HasBit(p2, 0)) bits &= DiagDirToRoadBits(dir); } - CommandCost ret = DoCommand(tile, drd << 6 | rt << 4 | bits | (is_ai ? 1 << 8 : 0), 0, flags, CMD_BUILD_ROAD); + CommandCost ret = DoCommand(tile, drd << 11 | rt << 4 | bits | (is_ai ? 1 << 13 : 0), 0, flags, CMD_BUILD_ROAD); if (ret.Failed()) { last_error = ret; if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) { @@ -1090,7 +1252,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) - * - p2 = (bit 3 + 4) - road type + * - p2 = (bit 3 - 8) - road type * @param text unused * @return the cost of this operation or an error */ @@ -1101,8 +1263,8 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 if (p1 >= MapSize()) return CMD_ERROR; TileIndex end_tile = p1; - RoadType rt = Extract(p2); - if (!IsValidRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ @@ -1130,7 +1292,8 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 /* try to remove the halves. */ if (bits != 0) { - CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true); + RoadTramType rtt = GetRoadTramType(rt); + CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rtt, true); if (ret.Succeeded()) { if (flags & DC_EXEC) { money -= ret.GetCost(); @@ -1138,7 +1301,7 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 _additional_cash_required = DoCommand(start_tile, end_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost(); return cost; } - RemoveRoad(tile, flags, bits, rt, true, false); + RemoveRoad(tile, flags, bits, rtt, true, false); } cost.AddCost(ret); had_success = true; @@ -1161,7 +1324,7 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 * @param tile tile where to build the depot * @param flags operation to perform * @param p1 bit 0..1 entrance direction (DiagDirection) - * bit 2..3 road type + * bit 2..7 road type * @param p2 unused * @param text unused * @return the cost of this operation or an error @@ -1172,9 +1335,9 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { DiagDirection dir = Extract(p1); - RoadType rt = Extract(p1); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p1); + if (!ValParamRoadType(rt)) return CMD_ERROR; CommandCost cost(EXPENSES_CONSTRUCTION); @@ -1198,8 +1361,7 @@ CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui dep->build_date = _date; /* A road depot has two road bits. */ - Company::Get(_current_company)->infrastructure.road[rt] += 2; - DirtyCompanyInfrastructureWindows(_current_company); + UpdateCompanyRoadInfrastructure(rt, _current_company, 2); MakeRoadDepot(tile, _current_company, dep->index, dir, rt); MarkTileDirtyByTile(tile); @@ -1225,7 +1387,9 @@ static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags) Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != nullptr) { /* A road depot has two road bits. */ - c->infrastructure.road[FIND_FIRST_BIT(GetRoadTypes(tile))] -= 2; + RoadType rt = GetRoadTypeRoad(tile); + if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile); + c->infrastructure.road[rt] -= 2; DirtyCompanyInfrastructureWindows(c->index); } @@ -1245,11 +1409,12 @@ static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags) RoadBits b = GetAllRoadBits(tile); /* Clear the road if only one piece is on the tile OR we are not using the DC_AUTO flag */ - if ((HasExactlyOneBit(b) && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) { + if ((HasExactlyOneBit(b) && GetRoadBits(tile, RTT_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) { CommandCost ret(EXPENSES_CONSTRUCTION); - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true); + FOR_ALL_ROADTRAMTYPES(rtt) { + if (!MayHaveRoad(tile) || GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue; + + CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rtt), rtt, true); if (tmp_ret.Failed()) return tmp_ret; ret.AddCost(tmp_ret); } @@ -1259,21 +1424,19 @@ static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags) } case ROAD_TILE_CROSSING: { - RoadTypes rts = GetRoadTypes(tile); CommandCost ret(EXPENSES_CONSTRUCTION); if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST); /* Must iterate over the roadtypes in a reverse manner because * tram tracks must be removed before the road bits. */ - RoadType rt = ROADTYPE_TRAM; - do { - if (HasBit(rts, rt)) { - CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false); - if (tmp_ret.Failed()) return tmp_ret; - ret.AddCost(tmp_ret); - } - } while (rt-- != ROADTYPE_ROAD); + for (RoadTramType rtt : { RTT_TRAM, RTT_ROAD }) { + if (GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue; + + CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rtt, false); + if (tmp_ret.Failed()) return tmp_ret; + ret.AddCost(tmp_ret); + } if (flags & DC_EXEC) { DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); @@ -1335,6 +1498,33 @@ const byte _road_sloped_sprites[14] = { 0, 0 }; +/** + * Get the sprite offset within a spritegroup. + * @param slope Slope + * @param bits Roadbits + * @return Offset for the sprite within the spritegroup. + */ +static uint GetRoadSpriteOffset(Slope slope, RoadBits bits) +{ + if (slope != SLOPE_FLAT) { + switch (slope) { + case SLOPE_NE: return 11; + case SLOPE_SE: return 12; + case SLOPE_SW: return 13; + case SLOPE_NW: return 14; + default: NOT_REACHED(); + } + } else { + static const uint offsets[] = { + 0, 18, 17, 7, + 16, 0, 10, 5, + 15, 8, 1, 4, + 9, 3, 6, 2 + }; + return offsets[bits]; + } +} + /** * Should the road be drawn as a unpaved snow/desert road? * By default, roads are always drawn as unpaved if they are on desert or @@ -1352,15 +1542,13 @@ static bool DrawRoadAsSnowDesert(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 + * Draws the catenary for the RoadType of the given tile + * @param ti information about the tile (slopes, height etc) + * @param rt road type to draw catenary for + * @param rb the roadbits for the tram */ -void DrawRoadCatenary(const TileInfo *ti, RoadBits tram) +void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb) { - /* Do not draw catenary if it is invisible */ - if (IsInvisibilitySet(TO_CATENARY)) return; - /* Don't draw the catenary under a low bridge */ if (IsBridgeAbove(ti->tile) && !IsTransparencySet(TO_CATENARY)) { int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); @@ -1368,19 +1556,89 @@ void DrawRoadCatenary(const TileInfo *ti, RoadBits tram) if (height <= GetTileMaxZ(ti->tile) + 1) return; } - SpriteID front; - SpriteID back; + if (CountBits(rb) > 2) { + /* On junctions we check whether neighbouring tiles also have catenary, and possibly + * do not draw catenary towards those neighbours, which do not have catenary. */ + RoadBits rb_new = ROAD_NONE; + for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { + if (rb & DiagDirToRoadBits(dir)) { + TileIndex neighbour = TileAddByDiagDir(ti->tile, dir); + if (MayHaveRoad(neighbour)) { + RoadType rt_road = GetRoadTypeRoad(neighbour); + RoadType rt_tram = GetRoadTypeTram(neighbour); + + if ((rt_road != INVALID_ROADTYPE && HasRoadCatenary(rt_road)) || + (rt_tram != INVALID_ROADTYPE && HasRoadCatenary(rt_tram))) { + rb_new |= DiagDirToRoadBits(dir); + } + } + } + } + if (CountBits(rb_new) >= 2) rb = rb_new; + } + + const RoadTypeInfo* rti = GetRoadTypeInfo(rt); + SpriteID front = GetCustomRoadSprite(rti, ti->tile, ROTSG_CATENARY_FRONT); + SpriteID back = GetCustomRoadSprite(rti, ti->tile, ROTSG_CATENARY_BACK); - if (ti->tileh != SLOPE_FLAT) { + if (front != 0 || back != 0) { + if (front != 0) front += GetRoadSpriteOffset(ti->tileh, rb); + if (back != 0) back += GetRoadSpriteOffset(ti->tileh, rb); + } else 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]; + back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[rb]; + front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[rb]; } - AddSortableSpriteToDraw(back, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); - AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); + /* Catenary uses 1st company colour to help identify owner. + * For tiles with OWNER_TOWN or OWNER_NONE, recolour CC to grey as a neutral colour. */ + Owner owner = GetRoadOwner(ti->tile, GetRoadTramType(rt)); + PaletteID pal = (owner == OWNER_NONE || owner == OWNER_TOWN ? GENERAL_SPRITE_COLOUR(COLOUR_GREY) : COMPANY_SPRITE_COLOUR(owner)); + if (back != 0) AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); + if (front != 0) AddSortableSpriteToDraw(front, pal, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); +} + +/** + * Draws the catenary for the given tile + * @param ti information about the tile (slopes, height etc) + */ +void DrawRoadCatenary(const TileInfo *ti) +{ + RoadBits road = ROAD_NONE; + RoadBits tram = ROAD_NONE; + + if (IsTileType(ti->tile, MP_ROAD)) { + if (IsNormalRoad(ti->tile)) { + road = GetRoadBits(ti->tile, RTT_ROAD); + tram = GetRoadBits(ti->tile, RTT_TRAM); + } else if (IsLevelCrossing(ti->tile)) { + tram = road = (GetCrossingRailAxis(ti->tile) == AXIS_Y ? ROAD_X : ROAD_Y); + } + } else if (IsTileType(ti->tile, MP_STATION)) { + if (IsRoadStop(ti->tile)) { + if (IsDriveThroughStopTile(ti->tile)) { + Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; + tram = road = (axis == AXIS_X ? ROAD_X : ROAD_Y); + } else { + tram = road = DiagDirToRoadBits(GetRoadStopDir(ti->tile)); + } + } + } else { + // No road here, no catenary to draw + return; + } + + RoadType rt = GetRoadTypeRoad(ti->tile); + if (rt != INVALID_ROADTYPE && HasRoadCatenaryDrawn(rt)) { + DrawRoadTypeCatenary(ti, rt, road); + } + + rt = GetRoadTypeTram(ti->tile); + if (rt != INVALID_ROADTYPE && HasRoadCatenaryDrawn(rt)) { + DrawRoadTypeCatenary(ti, rt, tram); + } } /** @@ -1401,57 +1659,124 @@ static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int } /** - * Draw ground sprite and road pieces + * Draw road underlay and overlay sprites. * @param ti TileInfo + * @param road_rti Road road type information + * @param tram_rti Tram road type information + * @param road_offset Road sprite offset (based on road bits) + * @param tram_offset Tram sprite offset (based on road bits) */ -void DrawRoadBits(TileInfo *ti) +void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, uint road_offset, uint tram_offset) { - const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE); - RoadBits road = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, ROADTYPE_ROAD) : GetRoadBits(ti->tile, ROADTYPE_ROAD); - RoadBits tram = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, ROADTYPE_TRAM) : GetRoadBits(ti->tile, ROADTYPE_TRAM); - - SpriteID image = 0; - PaletteID pal = PAL_NONE; - - if (ti->tileh != SLOPE_FLAT) { - DrawFoundation(ti, is_bridge ? FOUNDATION_LEVELED : GetRoadFoundation(ti->tileh, road | tram)); + /* Road underlay takes precedence over tram */ + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_GROUND); + DrawGroundSprite(ground + road_offset, pal); + } + } else { + if (tram_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_GROUND); + DrawGroundSprite(ground + tram_offset, pal); + } else { + DrawGroundSprite(SPR_TRAMWAY_TRAM + tram_offset, pal); + } + } - /* DrawFoundation() modifies ti. - * Default sloped sprites.. */ - if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + SPR_ROAD_SLOPE_START; + /* Draw road overlay */ + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + road_offset, pal); + } } - if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram]; + /* Draw tram overlay */ + if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + tram_offset, pal); + } else if (road_rti != nullptr) { + DrawGroundSprite(SPR_TRAMWAY_OVERLAY + tram_offset, pal); + } + } +} - Roadside roadside = is_bridge ? ROADSIDE_PAVED : GetRoadside(ti->tile); +/** + * Get ground sprite to draw for a road tile. + * @param ti TileInof + * @param roadside Road side type + * @param rti Road type info + * @param offset Road sprite offset + * @param[out] pal Palette to draw. + */ +static SpriteID GetRoadGroundSprite(const TileInfo *ti, Roadside roadside, const RoadTypeInfo *rti, uint offset, PaletteID *pal) +{ + /* Draw bare ground sprite if no road or road uses overlay system. */ + if (rti == nullptr || rti->UsesOverlay()) { + if (DrawRoadAsSnowDesert(ti->tile, roadside)) { + return SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh); + } + switch (roadside) { + case ROADSIDE_BARREN: *pal = PALETTE_TO_BARE_LAND; + return SPR_FLAT_GRASS_TILE + SlopeToSpriteOffset(ti->tileh); + case ROADSIDE_GRASS: + case ROADSIDE_GRASS_ROAD_WORKS: return SPR_FLAT_GRASS_TILE + SlopeToSpriteOffset(ti->tileh); + default: break; // Paved + } + } + /* Draw original road base sprite */ + SpriteID image = SPR_ROAD_Y + offset; if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 19; } else { switch (roadside) { - case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; + case ROADSIDE_BARREN: *pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; case ROADSIDE_GRASS_ROAD_WORKS: break; default: image -= 19; break; // Paved } } - DrawGroundSprite(image, pal); + return image; +} - /* 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); +/** + * Draw ground sprite and road pieces + * @param ti TileInfo + */ +void DrawRoadBits(TileInfo *ti) +{ + const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE); + RoadBits road = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, RTT_ROAD) : GetRoadBits(ti->tile, RTT_ROAD); + RoadBits tram = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, RTT_TRAM) : GetRoadBits(ti->tile, RTT_TRAM); + + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + if (ti->tileh != SLOPE_FLAT) { + DrawFoundation(ti, is_bridge ? FOUNDATION_LEVELED : GetRoadFoundation(ti->tileh, road | tram)); + /* DrawFoundation() modifies ti. */ } - if (!is_bridge && road != ROAD_NONE) { + /* Determine sprite offsets */ + uint road_offset = GetRoadSpriteOffset(ti->tileh, road); + uint tram_offset = GetRoadSpriteOffset(ti->tileh, tram); + + /* Draw baseset underlay */ + Roadside roadside = is_bridge ? ROADSIDE_PAVED : GetRoadside(ti->tile); + + PaletteID pal = PAL_NONE; + SpriteID image = GetRoadGroundSprite(ti, roadside, road_rti, road == ROAD_NONE ? tram_offset : road_offset, &pal); + DrawGroundSprite(image, pal); + + DrawRoadOverlays(ti, pal, road_rti, tram_rti, road_offset, tram_offset); + + /* Draw one way */ + if (!is_bridge && road_rti != nullptr) { DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile); if (drd != DRD_NONE) { DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh)); @@ -1464,7 +1789,8 @@ void DrawRoadBits(TileInfo *ti) return; } - if (tram != ROAD_NONE) DrawRoadCatenary(ti, tram); + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); /* 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; @@ -1499,41 +1825,38 @@ static void DrawTile_Road(TileInfo *ti) case ROAD_TILE_CROSSING: { if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); - PaletteID pal = PAL_NONE; + Axis axis = GetCrossingRailAxis(ti->tile); + const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + PaletteID pal = PAL_NONE; + + /* Draw base ground */ if (rti->UsesOverlay()) { - Axis axis = GetCrossingRailAxis(ti->tile); - SpriteID road = SPR_ROAD_Y + axis; + SpriteID image = SPR_ROAD_Y + axis; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(ti->tile, roadside)) { - road += 19; + image += 19; } else { switch (roadside) { case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; - default: road -= 19; break; // Paved + default: image -= 19; break; // Paved } } - DrawGroundSprite(road, pal); - - SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis; - /* Draw tracks, but draw PBS reserved tracks darker. */ - pal = (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) ? PALETTE_CRASH : PAL_NONE; - DrawGroundSprite(rail, pal); - - DrawRailTileSeq(ti, &_crossing_layout, TO_CATENARY, rail, 0, PAL_NONE); + DrawGroundSprite(image, pal); } else { - SpriteID image = rti->base_sprites.crossing; - - if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++; + SpriteID image = rti->base_sprites.crossing + axis; if (IsCrossingBarred(ti->tile)) image += 2; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 8; } else { @@ -1545,18 +1868,31 @@ static void DrawTile_Road(TileInfo *ti) } DrawGroundSprite(image, pal); - - /* PBS debugging, draw reserved tracks darker */ - if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) { - DrawGroundSprite(GetCrossingRoadAxis(ti->tile) == AXIS_Y ? GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_x : GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_y, PALETTE_CRASH); - } } - if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { - DrawGroundSprite(SPR_TRAMWAY_OVERLAY + (GetCrossingRoadAxis(ti->tile) ^ 1), pal); - DrawRoadCatenary(ti, GetCrossingRoadBits(ti->tile)); + DrawRoadOverlays(ti, pal, road_rti, tram_rti, axis, axis); + + /* Draw rail/PBS overlay */ + bool draw_pbs = _game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile); + if (rti->UsesOverlay()) { + PaletteID pal = draw_pbs ? PALETTE_CRASH : PAL_NONE; + SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis; + DrawGroundSprite(rail, pal); + + DrawRailTileSeq(ti, &_crossing_layout, TO_CATENARY, rail, 0, PAL_NONE); + } else if (draw_pbs || tram_rti != nullptr || road_rti->UsesOverlay()) { + /* Add another rail overlay, unless there is only the base road sprite. */ + PaletteID pal = draw_pbs ? PALETTE_CRASH : PAL_NONE; + SpriteID rail = GetCrossingRoadAxis(ti->tile) == AXIS_Y ? GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_x : GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_y; + DrawGroundSprite(rail, pal); } + + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); + + /* Draw rail catenary */ if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); + break; } @@ -1566,15 +1902,42 @@ static void DrawTile_Road(TileInfo *ti) PaletteID palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)); - const DrawTileSprites *dts; - if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { - dts = &_tram_depot[GetRoadDepotDirection(ti->tile)]; + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt == INVALID_ROADTYPE ? tram_rt : road_rt); + + int relocation = GetCustomRoadSprite(rti, ti->tile, ROTSG_DEPOT); + bool default_gfx = relocation == 0; + if (default_gfx) { + if (HasBit(rti->flags, ROTF_CATENARY)) { + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK && road_rt == INVALID_ROADTYPE && !rti->UsesOverlay()) { + /* Sprites with track only work for default tram */ + relocation = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_ROAD_DEPOT; + default_gfx = false; + } else { + /* Sprites without track are always better, if provided */ + relocation = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_ROAD_DEPOT; + } + } } else { - dts = &_road_depot[GetRoadDepotDirection(ti->tile)]; + relocation -= SPR_ROAD_DEPOT; } + DiagDirection dir = GetRoadDepotDirection(ti->tile); + const DrawTileSprites *dts = &_road_depot[dir]; DrawGroundSprite(dts->ground.sprite, PAL_NONE); - DrawOrigTileSeq(ti, dts, TO_BUILDINGS, palette); + + if (default_gfx) { + uint offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir)); + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + offset, PAL_NONE); + } else if (road_rt == INVALID_ROADTYPE) { + DrawGroundSprite(SPR_TRAMWAY_OVERLAY + offset, PAL_NONE); + } + } + + DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, palette); break; } } @@ -1591,10 +1954,39 @@ static void DrawTile_Road(TileInfo *ti) void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt) { PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); - const DrawTileSprites *dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir]; + const RoadTypeInfo* rti = GetRoadTypeInfo(rt); + int relocation = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_DEPOT); + bool default_gfx = relocation == 0; + if (default_gfx) { + if (HasBit(rti->flags, ROTF_CATENARY)) { + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK && RoadTypeIsTram(rt) && !rti->UsesOverlay()) { + /* Sprites with track only work for default tram */ + relocation = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_ROAD_DEPOT; + default_gfx = false; + } else { + /* Sprites without track are always better, if provided */ + relocation = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_ROAD_DEPOT; + } + } + } else { + relocation -= SPR_ROAD_DEPOT; + } + + const DrawTileSprites *dts = &_road_depot[dir]; DrawSprite(dts->ground.sprite, PAL_NONE, x, y); - DrawOrigTileSeqInGUI(x, y, dts, palette); + + if (default_gfx) { + uint offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir)); + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY); + if (ground != 0) DrawSprite(ground + offset, PAL_NONE, x, y); + } else if (RoadTypeIsTram(rt)) { + DrawSprite(SPR_TRAMWAY_OVERLAY + offset, PAL_NONE, x, y); + } + } + + DrawRailTileSeqInGUI(x, y, dts, relocation, 0, palette); } /** @@ -1732,11 +2124,19 @@ static void TileLoop_Road(TileIndex tile) if (_settings_game.economy.mod_road_rebuild) { /* Generate a nicer town surface */ - const RoadBits old_rb = GetAnyRoadBits(tile, ROADTYPE_ROAD); + const RoadBits old_rb = GetAnyRoadBits(tile, RTT_ROAD); const RoadBits new_rb = CleanUpRoadBits(tile, old_rb); if (old_rb != new_rb) { - RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), ROADTYPE_ROAD, true); + RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), RTT_ROAD, true); + } + } + + /* Possibly change road type */ + if (GetRoadOwner(tile, RTT_ROAD) == OWNER_TOWN) { + RoadType rt = GetTownRoadType(t); + if (rt != GetRoadTypeRoad(tile)) { + SetRoadType(tile, RTT_ROAD, rt); } } @@ -1781,18 +2181,18 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u if (IsLevelCrossing(tile)) trackdirbits = TrackBitsToTrackdirBits(GetCrossingRailBits(tile)); break; - case TRANSPORT_ROAD: - if ((GetRoadTypes(tile) & sub_mode) == 0) break; + case TRANSPORT_ROAD: { + RoadTramType rtt = (RoadTramType)sub_mode; + if (!HasTileRoadType(tile, rtt)) break; switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 }; - RoadType rt = (RoadType)FindFirstBit(sub_mode); - RoadBits bits = GetRoadBits(tile, rt); + RoadBits bits = GetRoadBits(tile, rtt); /* no roadbit at this side of tile, return 0 */ if (side != INVALID_DIAGDIR && (DiagDirToRoadBits(side) & bits) == 0) break; - uint multiplier = drd_to_multiplier[rt == ROADTYPE_TRAM ? DRD_NONE : GetDisallowedRoadDirections(tile)]; + uint multiplier = drd_to_multiplier[(rtt == RTT_TRAM) ? DRD_NONE : GetDisallowedRoadDirections(tile)]; if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier); break; } @@ -1826,6 +2226,7 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u } } break; + } default: break; } @@ -1849,13 +2250,25 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc *td) Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } + switch (GetRoadTileType(tile)) { case ROAD_TILE_CROSSING: { td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING; - RoadTypes rts = GetRoadTypes(tile); rail_owner = GetTileOwner(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->railtype = rti->strings.name; @@ -1866,15 +2279,11 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc *td) case ROAD_TILE_DEPOT: td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT; - road_owner = GetTileOwner(tile); // Tile has only one owner, roadtype does not matter td->build_date = Depot::GetByTile(tile)->build_date; break; default: { - RoadTypes rts = GetRoadTypes(tile); - td->str = (HasBit(rts, ROADTYPE_ROAD) ? _road_tile_strings[GetRoadside(tile)] : STR_LAI_ROAD_DESCRIPTION_TRAMWAY); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + td->str = (road_rt != INVALID_ROADTYPE ? _road_tile_strings[GetRoadside(tile)] : STR_LAI_ROAD_DESCRIPTION_TRAMWAY); break; } } @@ -1951,14 +2360,15 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); } else { /* A road depot has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ - RoadType rt = (RoadType)FIND_FIRST_BIT(GetRoadTypes(tile)); + RoadType rt = GetRoadTypeRoad(tile); + if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile); Company::Get(old_owner)->infrastructure.road[rt] -= 2; Company::Get(new_owner)->infrastructure.road[rt] += 2; SetTileOwner(tile, new_owner); - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { - if (GetRoadOwner(tile, rt) == old_owner) { - SetRoadOwner(tile, rt, new_owner); + FOR_ALL_ROADTRAMTYPES(rtt) { + if (GetRoadOwner(tile, rtt) == old_owner) { + SetRoadOwner(tile, rtt, new_owner); } } } @@ -1966,17 +2376,18 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne return; } - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - if (HasTileRoadType(tile, rt)) { + if (GetRoadOwner(tile, rtt) == old_owner) { + RoadType rt = GetRoadType(tile, rtt); + if (rt != INVALID_ROADTYPE) { /* A level crossing has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ - uint num_bits = IsLevelCrossing(tile) ? 2 : CountBits(GetRoadBits(tile, rt)); + uint num_bits = IsLevelCrossing(tile) ? 2 : CountBits(GetRoadBits(tile, rtt)); Company::Get(old_owner)->infrastructure.road[rt] -= num_bits; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_bits; } - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } @@ -2035,6 +2446,256 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } +/** Update power of road vehicle under which is the roadtype being converted */ +static Vehicle *UpdateRoadVehPowerProc(Vehicle *v, void *data) +{ + if (v->type != VEH_ROAD) return nullptr; + + RoadVehicleList *affected_rvs = static_cast(data); + include(*affected_rvs, RoadVehicle::From(v)->First()); + + return nullptr; +} + +/** + * Checks the tile and returns whether the current player is allowed to convert the roadtype to another roadtype + * @param owner the tile owner. + * @param rtt Road/tram type. + * @return whether the road is convertible + */ +static bool CanConvertRoadType(Owner owner, RoadTramType rtt) +{ + return (owner == OWNER_NONE || (owner == OWNER_TOWN && rtt == RTT_ROAD)); +} + +/** + * Convert the ownership of the RoadType of the tile if applyable + * @param tile the tile of which convert ownership + * @param num_pieces the count of the roadbits to assign to the new owner + * @param owner the current owner of the RoadType + * @param from_type the old road type + * @param to_type the new road type + */ +static void ConvertRoadTypeOwner(TileIndex tile, uint num_pieces, Owner owner, RoadType from_type, RoadType to_type) +{ + // Scenario editor, maybe? Don't touch the owners when converting roadtypes... + if (_current_company >= MAX_COMPANIES) return; + + // We can't get a company from invalid owners but we can get ownership of roads without an owner + if (owner >= MAX_COMPANIES && owner != OWNER_NONE) return; + + Company *c; + + switch (owner) { + case OWNER_NONE: + SetRoadOwner(tile, GetRoadTramType(to_type), (Owner)_current_company); + UpdateCompanyRoadInfrastructure(to_type, _current_company, num_pieces); + break; + + default: + c = Company::Get(owner); + c->infrastructure.road[from_type] -= num_pieces; + c->infrastructure.road[to_type] += num_pieces; + DirtyCompanyInfrastructureWindows(c->index); + break; + } +} + +/** + * Convert one road subtype to another. + * Not meant to convert from road to tram. + * + * @param tile end tile of road conversion drag + * @param flags operation to perform + * @param p1 start tile of drag + * @param p2 various bitstuffed elements: + * - p2 = (bit 0..5) new roadtype to convert to. + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + RoadType to_type = Extract(p2); + + TileIndex area_start = p1; + TileIndex area_end = tile; + + if (!ValParamRoadType(to_type)) return CMD_ERROR; + if (area_start >= MapSize()) return CMD_ERROR; + + RoadVehicleList affected_rvs; + RoadTramType rtt = GetRoadTramType(to_type); + + CommandCost cost(EXPENSES_CONSTRUCTION); + CommandCost error = CommandCost((rtt == RTT_TRAM) ? STR_ERROR_NO_SUITABLE_TRAMWAY : STR_ERROR_NO_SUITABLE_ROAD); // by default, there is no road to convert. + + TileIterator *iter = new OrthogonalTileIterator(area_start, area_end); + for (; (tile = *iter) != INVALID_TILE; ++(*iter)) { + /* Is road present on tile? */ + if (!MayHaveRoad(tile)) continue; + + /* Converting to the same subtype? */ + RoadType from_type = GetRoadType(tile, rtt); + if (from_type == INVALID_ROADTYPE || from_type == to_type) continue; + + /* Check if there is any infrastructure on tile */ + TileType tt = GetTileType(tile); + switch (tt) { + case MP_STATION: + if (!IsRoadStop(tile)) continue; + break; + case MP_ROAD: + if (IsLevelCrossing(tile) && RoadNoLevelCrossing(to_type)) { + error.MakeError(STR_ERROR_CROSSING_DISALLOWED_ROAD); + continue; + } + break; + case MP_TUNNELBRIDGE: + if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) continue; + break; + default: continue; + } + + /* Trying to convert other's road */ + Owner owner = GetRoadOwner(tile, rtt); + if (!CanConvertRoadType(owner, rtt)) { + CommandCost ret = CheckOwnership(owner, tile); + if (ret.Failed()) { + error = ret; + continue; + } + } + + /* Vehicle on the tile when not converting normal <-> powered + * Tunnels and bridges have special check later */ + if (tt != MP_TUNNELBRIDGE) { + if (!HasPowerOnRoad(from_type, to_type)) { + CommandCost ret = EnsureNoVehicleOnGround(tile); + if (ret.Failed()) { + error = ret; + continue; + } + + if (rtt == RTT_ROAD && owner == OWNER_TOWN) { + error.MakeError(STR_ERROR_INCOMPATIBLE_ROAD); + continue; + } + } + + uint num_pieces = CountBits(GetAnyRoadBits(tile, rtt));; + cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type)); + + if (flags & DC_EXEC) { // we can safely convert, too + /* Update the company infrastructure counters. */ + if (!IsRoadStopTile(tile) && CanConvertRoadType(owner, rtt) && owner != OWNER_TOWN) { + ConvertRoadTypeOwner(tile, num_pieces, owner, from_type, to_type); + } else { + UpdateCompanyRoadInfrastructure(from_type, owner, -num_pieces); + UpdateCompanyRoadInfrastructure(to_type, owner, num_pieces); + } + + /* Perform the conversion */ + SetRoadType(tile, rtt, to_type); + MarkTileDirtyByTile(tile); + + /* update power of train on this tile */ + FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); + + if (IsRoadDepotTile(tile)) { + /* Update build vehicle window related to this depot */ + InvalidateWindowData(WC_VEHICLE_DEPOT, tile); + InvalidateWindowData(WC_BUILD_VEHICLE, tile); + } + } + } else { + TileIndex endtile = GetOtherTunnelBridgeEnd(tile); + + const bool include_middle = !IsBridge(tile) || GetCustomBridgeHeadRoadBits(tile, rtt) & DiagDirToRoadBits(GetTunnelBridgeDirection(tile)); + + /* If both ends of tunnel/bridge are in the range, do not try to convert twice - + * it would cause assert because of different test and exec runs */ + if (include_middle && endtile < tile) { + if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue; + } + + /* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */ + if (!HasPowerOnRoad(from_type, to_type)) { + CommandCost ret = TunnelBridgeIsFree(tile, endtile); + if (ret.Failed()) { + error = ret; + continue; + } + + if (rtt == RTT_ROAD && owner == OWNER_TOWN) { + error.MakeError(STR_ERROR_INCOMPATIBLE_ROAD); + continue; + } + } + + /* There are 2 pieces on *every* tile of the bridge or tunnel */ + uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * 2; + cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type)); + + uint tunnel_length = GetTunnelBridgeLength(tile, endtile); + auto num_pieces_per_side = [tunnel_length, rtt](TileIndex t, bool middle) -> uint { + uint num_pieces = 0; + if (IsBridge(t)) { + const RoadBits bits = GetCustomBridgeHeadRoadBits(t, rtt); + num_pieces += CountBits(bits) * TUNNELBRIDGE_TRACKBIT_FACTOR; + } else { + num_pieces += 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; + } + if (middle) { + num_pieces += 2 * tunnel_length * TUNNELBRIDGE_TRACKBIT_FACTOR; + } + return num_pieces; + }; + uint tile_pieces = num_pieces_per_side(tile, include_middle); + uint end_pieces = include_middle ? num_pieces_per_side(endtile, false) : 0; + cost.AddCost((tile_pieces + end_pieces) * RoadConvertCost(from_type, to_type)); + + if (flags & DC_EXEC) { + /* Update the company infrastructure counters. */ + if (CanConvertRoadType(owner, rtt) && owner != OWNER_TOWN) { + ConvertRoadTypeOwner(tile, tile_pieces, owner, from_type, to_type); + if (include_middle) { + ConvertRoadTypeOwner(endtile, end_pieces, owner, from_type, to_type); + SetTunnelBridgeOwner(tile, endtile, _current_company); + } + } else { + UpdateCompanyRoadInfrastructure(from_type, owner, -(tile_pieces + end_pieces)); + UpdateCompanyRoadInfrastructure(to_type, owner, tile_pieces + end_pieces); + } + + /* Perform the conversion */ + SetRoadType(tile, rtt, to_type); + if (include_middle) SetRoadType(endtile, rtt, to_type); + + FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); + FindVehicleOnPos(endtile, &affected_rvs, &UpdateRoadVehPowerProc); + + if (IsBridge(tile)) { + MarkBridgeDirty(tile); + } else { + MarkTileDirtyByTile(tile); + MarkTileDirtyByTile(endtile); + } + } + } + } + + if (flags & DC_EXEC) { + /* Roadtype changed, update roadvehicles as when entering different track */ + for (RoadVehicle *v : affected_rvs) { + v->CargoChanged(); + } + } + + delete iter; + return (cost.GetCost() == 0) ? error : cost; +} + + /** Tile callback functions for road tiles */ extern const TileTypeProcs _tile_type_road_procs = { DrawTile_Road, // draw_tile_proc diff --git a/src/road_func.h b/src/road_func.h index 261cfcf3cf..8571f85a81 100644 --- a/src/road_func.h +++ b/src/road_func.h @@ -13,29 +13,9 @@ #define ROAD_FUNC_H #include "core/bitmath_func.hpp" -#include "road_type.h" +#include "road.h" #include "economy_func.h" - -/** - * Iterate through each set RoadType in a RoadTypes value. - * For more informations see FOR_EACH_SET_BIT_EX. - * - * @param var Loop index variable that stores fallowing set road type. Must be of type RoadType. - * @param road_types The value to iterate through (any expression). - * - * @see FOR_EACH_SET_BIT_EX - */ -#define FOR_EACH_SET_ROADTYPE(var, road_types) FOR_EACH_SET_BIT_EX(RoadType, var, RoadTypes, road_types) - -/** - * Whether the given roadtype is valid. - * @param rt the roadtype to check for validness - * @return true if and only if valid - */ -static inline bool IsValidRoadType(RoadType rt) -{ - return rt == ROADTYPE_ROAD || rt == ROADTYPE_TRAM; -} +#include "transparency.h" /** * Whether the given roadtype is valid. @@ -47,32 +27,6 @@ static inline bool IsValidRoadBits(RoadBits r) return r < ROAD_END; } -/** - * Maps a RoadType to the corresponding RoadTypes value - * - * @param rt the roadtype to get the roadtypes from - * @return the roadtypes with the given roadtype - */ -static inline RoadTypes RoadTypeToRoadTypes(RoadType rt) -{ - assert(IsValidRoadType(rt)); - return (RoadTypes)(1 << rt); -} - -/** - * Returns the RoadTypes which are not present in the given RoadTypes - * - * This function returns the complement of a given RoadTypes. - * - * @param r The given RoadTypes - * @return The complement of the given RoadTypes - */ -static inline RoadTypes ComplementRoadTypes(RoadTypes r) -{ - return (RoadTypes)(ROADTYPES_ALL ^ r); -} - - /** * Calculate the complement of a RoadBits value * @@ -167,27 +121,53 @@ static inline RoadBits AxisToRoadBits(Axis a) * Calculates the maintenance cost of a number of road bits. * @param roadtype Road type to get the cost for. * @param num Number of road bits. + * @param total_num Total number of road bits of all road/tram-types. * @return Total cost. */ -static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num) +static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num, uint32 total_num) +{ + assert(roadtype < ROADTYPE_END); + return (_price[PR_INFRASTRUCTURE_ROAD] * GetRoadTypeInfo(roadtype)->maintenance_multiplier * num * (1 + IntSqrt(total_num))) >> 12; +} + +/** + * Test if a road type has catenary + * @param roadtype Road type to test + */ +static inline bool HasRoadCatenary(RoadType roadtype) { - assert(IsValidRoadType(roadtype)); - return (_price[PR_INFRASTRUCTURE_ROAD] * (roadtype == ROADTYPE_TRAM ? 3 : 2) * num * (1 + IntSqrt(num))) >> 9; // 2 bits fraction for the multiplier and 7 bits scaling. + assert(roadtype < ROADTYPE_END); + return HasBit(GetRoadTypeInfo(roadtype)->flags, ROTF_CATENARY); } -bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts); -bool ValParamRoadType(const RoadType rt); -RoadTypes GetCompanyRoadtypes(const CompanyID company); +/** + * Test if we should draw road catenary + * @param roadtype Road type to test + */ +static inline bool HasRoadCatenaryDrawn(RoadType roadtype) +{ + return HasRoadCatenary(roadtype) && !IsInvisibilitySet(TO_CATENARY); +} + +bool HasRoadTypeAvail(CompanyID company, RoadType roadtype); +bool ValParamRoadType(RoadType roadtype); +RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces = true); +RoadTypes GetRoadTypes(bool introduces); +RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, Date date); void UpdateLevelCrossing(TileIndex tile, bool sound = true, bool force_close = false); bool IsCrossingOccupiedByRoadVehicle(TileIndex t); +void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count); + +struct TileInfo; +void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rit, uint road_offset, uint tram_offset); inline void NotifyRoadLayoutChanged() { _road_layout_change_counter++; } -void NotifyRoadLayoutChangedIfTileNonLeaf(TileIndex tile, RoadType rt, RoadBits present_bits); -void NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(TileIndex start, TileIndex end, DiagDirection start_dir, RoadType rt); +void NotifyRoadLayoutChangedIfTileNonLeaf(TileIndex tile, RoadTramType rtt, RoadBits present_bits); +void NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(TileIndex start, TileIndex end, DiagDirection start_dir, RoadTramType rtt); #endif /* ROAD_FUNC_H */ diff --git a/src/road_gui.cpp b/src/road_gui.cpp index e0158d24bc..7f79c43e7d 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -29,6 +29,10 @@ #include "hotkeys.h" #include "road_gui.h" #include "zoom_func.h" +#include "engine_base.h" +#include "strings_func.h" +#include "core/geometry_func.hpp" +#include "date_func.h" #include "widgets/road_widget.h" @@ -110,52 +114,6 @@ void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p } } -/** Structure holding information per roadtype for several functions */ -struct RoadTypeInfo { - StringID err_build_road; ///< Building a normal piece of road - StringID err_remove_road; ///< Removing a normal piece of road - StringID err_depot; ///< Building a depot - StringID err_build_station[2]; ///< Building a bus or truck station - StringID err_remove_station[2]; ///< Removing of a bus or truck station - - StringID picker_title[2]; ///< Title for the station picker for bus or truck stations - StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations - - SpriteID cursor_nesw; ///< Cursor for building NE and SW bits - SpriteID cursor_nwse; ///< Cursor for building NW and SE bits - SpriteID cursor_autoroad; ///< Cursor for building autoroad -}; - -/** What errors/cursors must be shown for several types of roads */ -static const RoadTypeInfo _road_type_infos[] = { - { - STR_ERROR_CAN_T_BUILD_ROAD_HERE, - STR_ERROR_CAN_T_REMOVE_ROAD_FROM, - STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, - { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, - { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, - { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, - { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_ROAD_NESW, - SPR_CURSOR_ROAD_NWSE, - SPR_CURSOR_AUTOROAD, - }, - { - STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, - STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, - STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, - { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, - { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_TRAMWAY_NESW, - SPR_CURSOR_TRAMWAY_NWSE, - SPR_CURSOR_AUTOTRAM, - }, -}; - /** * If required, connects a new structure to an existing road or tram by building the missing roadbit. * @param tile Tile containing the structure to connect. @@ -166,7 +124,7 @@ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction) tile += TileOffsByDiagDir(direction); /* if there is a roadpiece just outside of the station entrance, build a connecting route */ if (IsNormalRoadTile(tile)) { - if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) { + if (GetRoadBits(tile, GetRoadTramType(_cur_roadtype)) != ROAD_NONE) { DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD); } } @@ -190,9 +148,10 @@ void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2 * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * bit 6..7: Entrance direction (#DiagDirection). + * bit 2: Allow stations directly adjacent to other stations. + * bit 3..4: Entrance direction (#DiagDirection) for normal stops. + * bit 3: #Axis of the road for drive-through stops. + * bit 5..9: The roadtype. * bit 16..31: Station ID to join (NEW_STATION if build new one). * @see CmdBuildRoadStop */ @@ -200,7 +159,7 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; - DiagDirection dir = (DiagDirection)GB(p2, 6, 2); + DiagDirection dir = (DiagDirection)GB(p2, 3, 2); if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8)); @@ -216,8 +175,8 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) * @param start_tile First tile of the area. * @param end_tile Last tile of the area. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. + * bit 2: Allow stations directly adjacent to other stations. + * bit 5..10: The roadtypes. * @param cmd Command to use. * @see CcRoadStop() */ @@ -230,7 +189,7 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u SetBit(p2, 1); // It's a drive-through stop. ddir -= DIAGDIR_END; // Adjust picker result to actual direction. } - p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. + p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4. TileArea ta(start_tile, end_tile); CommandContainer cmdcont = { ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop, 0, "" }; @@ -309,15 +268,20 @@ static bool RoadToolbar_CtrlChanged(Window *w) /** Road toolbar window handler. */ struct BuildRoadToolbarWindow : Window { - int last_started_action; ///< Last started user action. + RoadType roadtype; ///< Road type to build. + const RoadTypeInfo *rti; ///< Informations about current road type + int last_started_action; ///< Last started user action. BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { + this->Initialize(_cur_roadtype); this->InitNested(window_number); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetupRoadToolbar(); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + } this->OnInvalidateData(); this->last_started_action = WIDGET_LIST_END; @@ -340,7 +304,8 @@ struct BuildRoadToolbarWindow : Window { { if (!gui_scope) return; - bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD); + if (_game_mode != GM_EDITOR && !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) delete this; + bool can_build = _game_mode != GM_EDITOR; this->SetWidgetsDisabledState(!can_build, WID_ROT_DEPOT, WID_ROT_BUS_STATION, @@ -353,6 +318,53 @@ struct BuildRoadToolbarWindow : Window { } } + void Initialize(RoadType roadtype) + { + assert(roadtype < ROADTYPE_END); + this->roadtype = roadtype; + this->rti = GetRoadTypeInfo(this->roadtype); + } + + /** + * Configures the road toolbar for roadtype given + * @param roadtype the roadtype to display + */ + void SetupRoadToolbar() + { + this->GetWidget(WID_ROT_ROAD_X)->widget_data = rti->gui_sprites.build_x_road; + this->GetWidget(WID_ROT_ROAD_Y)->widget_data = rti->gui_sprites.build_y_road; + this->GetWidget(WID_ROT_AUTOROAD)->widget_data = rti->gui_sprites.auto_road; + if (_game_mode != GM_EDITOR) { + this->GetWidget(WID_ROT_DEPOT)->widget_data = rti->gui_sprites.build_depot; + } + this->GetWidget(WID_ROT_CONVERT_ROAD)->widget_data = rti->gui_sprites.convert_road; + this->GetWidget(WID_ROT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; + } + + /** + * Switch to another road type. + * @param roadtype New road type. + */ + void ModifyRoadType(RoadType roadtype) + { + this->Initialize(roadtype); + this->SetupRoadToolbar(); + this->ReInit(); + } + + void SetStringParameters(int widget) const override + { + if (widget == WID_ROT_CAPTION) { + if (this->rti->max_speed > 0) { + SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY); + SetDParam(1, this->rti->strings.toolbar_caption); + SetDParam(2, this->rti->max_speed / 2); + } else { + SetDParam(0, this->rti->strings.toolbar_caption); + } + } + } + /** * Update the remove button lowered state of the road toolbar * @@ -365,8 +377,11 @@ struct BuildRoadToolbarWindow : Window { * Both are only valid if they are able to apply as options. */ switch (clicked_widget) { case WID_ROT_REMOVE: - this->RaiseWidget(WID_ROT_ONE_WAY); - this->SetWidgetDirty(WID_ROT_ONE_WAY); + if (RoadTypeIsRoad(this->roadtype)) { + this->RaiseWidget(WID_ROT_ONE_WAY); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + } + break; case WID_ROT_ONE_WAY: @@ -376,30 +391,30 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_BUS_STATION: case WID_ROT_TRUCK_STATION: - this->DisableWidget(WID_ROT_ONE_WAY); + if (RoadTypeIsRoad(this->roadtype)) this->DisableWidget(WID_ROT_ONE_WAY); this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); break; case WID_ROT_ROAD_X: case WID_ROT_ROAD_Y: case WID_ROT_AUTOROAD: - this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, !this->IsWidgetLowered(clicked_widget)); + } break; default: /* When any other buttons than road/station, raise and * disable the removal button */ - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - this->SetWidgetsLoweredState(false, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); + this->SetWidgetLoweredState(WID_ROT_REMOVE, false); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + this->SetWidgetLoweredState(WID_ROT_ONE_WAY, false); + } + break; } } @@ -410,17 +425,17 @@ struct BuildRoadToolbarWindow : Window { _one_way_button_clicked = false; switch (widget) { case WID_ROT_ROAD_X: - HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT); + HandlePlacePushButton(this, WID_ROT_ROAD_X, this->rti->cursor.road_nwse, HT_RECT); this->last_started_action = widget; break; case WID_ROT_ROAD_Y: - HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT); + HandlePlacePushButton(this, WID_ROT_ROAD_Y, this->rti->cursor.road_swne, HT_RECT); this->last_started_action = widget; break; case WID_ROT_AUTOROAD: - HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); + HandlePlacePushButton(this, WID_ROT_AUTOROAD, this->rti->cursor.autoroad, HT_RECT); this->last_started_action = widget; break; @@ -430,15 +445,15 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_DEPOT: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; + if (HandlePlacePushButton(this, WID_ROT_DEPOT, this->rti->cursor.depot, HT_RECT)) { ShowRoadDepotPicker(this); this->last_started_action = widget; } break; case WID_ROT_BUS_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_BUS); this->last_started_action = widget; @@ -446,7 +461,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_TRUCK_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_TRUCK); this->last_started_action = widget; @@ -466,7 +481,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_BUILD_TUNNEL: - HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL | HT_TUNNEL); + HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, this->rti->cursor.tunnel, HT_SPECIAL | HT_TUNNEL); this->last_started_action = widget; break; @@ -478,6 +493,11 @@ struct BuildRoadToolbarWindow : Window { if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; + case WID_ROT_CONVERT_ROAD: + HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, this->rti->cursor.convert_road, HT_RECT); + this->last_started_action = widget; + break; + default: NOT_REACHED(); } this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget); @@ -493,7 +513,7 @@ struct BuildRoadToolbarWindow : Window { void OnPlaceObject(Point pt, TileIndex tile) override { _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); - _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); + _one_way_button_clicked = RoadTypeIsRoad(this->roadtype) ? this->IsWidgetLowered(WID_ROT_ONE_WAY) : false; switch (this->last_started_action) { case WID_ROT_ROAD_X: _place_road_flag = RF_DIR_X; @@ -520,7 +540,7 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_DEPOT: DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, - CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); + CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot); break; case WID_ROT_BUS_STATION: @@ -536,10 +556,14 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_BUILD_TUNNEL: - DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + DoCommandP(tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); break; + case WID_ROT_CONVERT_ROAD: + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_ROAD); + break; + default: NOT_REACHED(); } } @@ -549,12 +573,13 @@ struct BuildRoadToolbarWindow : Window { if (_game_mode != GM_EDITOR && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); this->RaiseButtons(); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); this->SetWidgetDirty(WID_ROT_REMOVE); - this->SetWidgetDirty(WID_ROT_ONE_WAY); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + } DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); @@ -613,7 +638,7 @@ struct BuildRoadToolbarWindow : Window { default: NOT_REACHED(); case DDSP_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, _cur_roadtype); break; case DDSP_DEMOLISH_AREA: @@ -627,12 +652,16 @@ struct BuildRoadToolbarWindow : Window { * Use the first three bits (0x07) if dir == Y * else use the last 2 bits (X dir has * not the 3rd bit set) */ + + /* Even if _cur_roadtype_id is a uint8 we only use 5 bits so + * we could ignore the last 3 bits and reuse them for other + * flags */ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), + DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 10), _remove_button_clicked ? - CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : - CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound_SPLAT_OTHER); + CMD_REMOVE_LONG_ROAD | CMD_MSG(this->rti->strings.err_remove_road) : + CMD_BUILD_LONG_ROAD | CMD_MSG(this->rti->strings.err_build_road), CcPlaySound_SPLAT_OTHER); break; case DDSP_BUILD_BUSSTOP: @@ -640,9 +669,9 @@ struct BuildRoadToolbarWindow : Window { if (this->IsWidgetLowered(WID_ROT_BUS_STATION)) { if (_remove_button_clicked) { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound_SPLAT_OTHER); + DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_SPLAT_OTHER); } else { - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); + PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS])); } } break; @@ -652,19 +681,23 @@ struct BuildRoadToolbarWindow : Window { if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION)) { if (_remove_button_clicked) { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_SPLAT_OTHER); + DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_SPLAT_OTHER); } else { - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK])); + PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK])); } } break; + + case DDSP_CONVERT_ROAD: + DoCommandP(end_tile, start_tile, _cur_roadtype, CMD_CONVERT_ROAD | CMD_MSG(rti->strings.err_convert_road), CcPlaySound_SPLAT_OTHER); + break; } } } void OnPlacePresize(Point pt, TileIndex tile) override { - DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); + DoCommand(tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); } @@ -674,34 +707,36 @@ struct BuildRoadToolbarWindow : Window { return ES_NOT_HANDLED; } - static HotkeyList hotkeys; + static HotkeyList road_hotkeys; + static HotkeyList tram_hotkeys; }; /** * Handler for global hotkeys of the BuildRoadToolbarWindow. * @param hotkey Hotkey + * @param last_build Last build road type * @return ES_HANDLED if hotkey was accepted. */ -static EventState RoadToolbarGlobalHotkeys(int hotkey) +static EventState RoadTramToolbarGlobalHotkeys(int hotkey, RoadType last_build) { - Window *w = nullptr; - switch (_game_mode) { - case GM_NORMAL: { - extern RoadType _last_built_roadtype; - w = ShowBuildRoadToolbar(_last_built_roadtype); - break; - } + Window *w = (_game_mode == GM_NORMAL) ? ShowBuildRoadToolbar(last_build) : ShowBuildRoadScenToolbar(last_build); + if (w == nullptr) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} - case GM_EDITOR: - w = ShowBuildRoadScenToolbar(); - break; +static EventState RoadToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode == GM_NORMAL && !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_ROAD)) return ES_NOT_HANDLED; - default: - break; - } + extern RoadType _last_built_roadtype; + return RoadTramToolbarGlobalHotkeys(hotkey, _last_built_roadtype); +} - if (w == nullptr) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); +static EventState TramToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)) return ES_NOT_HANDLED; + extern RoadType _last_built_tramtype; + return RoadTramToolbarGlobalHotkeys(hotkey, _last_built_tramtype); } static Hotkey roadtoolbar_hotkeys[] = { @@ -716,15 +751,32 @@ static Hotkey roadtoolbar_hotkeys[] = { Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), Hotkey('R', "remove", WID_ROT_REMOVE), + Hotkey('C', "convert", WID_ROT_CONVERT_ROAD), HOTKEY_LIST_END }; -HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); +HotkeyList BuildRoadToolbarWindow::road_hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); + +static Hotkey tramtoolbar_hotkeys[] = { + Hotkey('1', "build_x", WID_ROT_ROAD_X), + Hotkey('2', "build_y", WID_ROT_ROAD_Y), + Hotkey('3', "autoroad", WID_ROT_AUTOROAD), + Hotkey('4', "demolish", WID_ROT_DEMOLISH), + Hotkey('5', "depot", WID_ROT_DEPOT), + Hotkey('6', "bus_station", WID_ROT_BUS_STATION), + Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), + Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), + Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), + Hotkey('R', "remove", WID_ROT_REMOVE), + Hotkey('C', "convert", WID_ROT_CONVERT_ROAD), + HOTKEY_LIST_END +}; +HotkeyList BuildRoadToolbarWindow::tram_hotkeys("tramtoolbar", tramtoolbar_hotkeys, TramToolbarGlobalHotkeys); static const NWidgetPart _nested_build_road_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -751,6 +803,8 @@ static const NWidgetPart _nested_build_road_widgets[] = { SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD), EndContainer(), }; @@ -759,13 +813,13 @@ static WindowDesc _build_road_desc( WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_widgets, lengthof(_nested_build_road_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::road_hotkeys ); static const NWidgetPart _nested_build_tramway_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -784,13 +838,14 @@ static const NWidgetPart _nested_build_tramway_widgets[] = { NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM), EndContainer(), }; @@ -799,7 +854,7 @@ static WindowDesc _build_tramway_desc( WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::tram_hotkeys ); /** @@ -812,16 +867,18 @@ static WindowDesc _build_tramway_desc( Window *ShowBuildRoadToolbar(RoadType roadtype) { if (!Company::IsValidID(_local_company)) return nullptr; - _cur_roadtype = roadtype; + if (!ValParamRoadType(roadtype)) return nullptr; DeleteWindowByClass(WC_BUILD_TOOLBAR); - return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); + _cur_roadtype = roadtype; + + return AllocateWindowDescFront(RoadTypeIsRoad(_cur_roadtype) ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); } static const NWidgetPart _nested_build_road_scen_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -842,6 +899,8 @@ static const NWidgetPart _nested_build_road_scen_widgets[] = { SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD), EndContainer(), }; @@ -850,17 +909,54 @@ static WindowDesc _build_road_scen_desc( WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::road_hotkeys +); + +static const NWidgetPart _nested_build_tramway_scen_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM), + EndContainer(), +}; + +static WindowDesc _build_tramway_scen_desc( + WDP_AUTO, "toolbar_tram_scen", 0, 0, + WC_SCEN_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_tramway_scen_widgets, lengthof(_nested_build_tramway_scen_widgets), + &BuildRoadToolbarWindow::tram_hotkeys ); /** * Show the road building toolbar in the scenario editor. * @return The just opened toolbar, or \c nullptr if the toolbar was already open. */ -Window *ShowBuildRoadScenToolbar() +Window *ShowBuildRoadScenToolbar(RoadType roadtype) { - _cur_roadtype = ROADTYPE_ROAD; - return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); + DeleteWindowById(WC_SCEN_BUILD_TOOLBAR, TRANSPORT_ROAD); + _cur_roadtype = roadtype; + + return AllocateWindowDescFront(RoadTypeIsRoad(_cur_roadtype) ? &_build_road_scen_desc : &_build_tramway_scen_desc, TRANSPORT_ROAD); } struct BuildRoadDepotWindow : public PickerWindowBase { @@ -869,7 +965,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { this->CreateNestedTree(); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); - if ( _cur_roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(_cur_roadtype)) { this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; } @@ -960,13 +1056,14 @@ struct BuildRoadStationWindow : public PickerWindowBase { this->CreateNestedTree(); /* Trams don't have non-drivethrough stations */ - if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) { + if (RoadTypeIsTram(_cur_roadtype) && _road_station_picker_orientation < DIAGDIR_END) { _road_station_picker_orientation = DIAGDIR_END; } + const RoadTypeInfo *rti = GetRoadTypeInfo(_cur_roadtype); + this->GetWidget(WID_BROS_CAPTION)->widget_data = rti->strings.picker_title[rs]; - this->GetWidget(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs]; - for (uint i = (_cur_roadtype == ROADTYPE_TRAM ? WID_BROS_STATION_X : WID_BROS_STATION_NE); i < WID_BROS_LT_OFF; i++) { - this->GetWidget(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs]; + for (uint i = RoadTypeIsTram(_cur_roadtype) ? WID_BROS_STATION_X : WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) { + this->GetWidget(i)->tool_tip = rti->strings.picker_tooltip[rs]; } this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); @@ -1023,7 +1120,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; - StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); + StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, _cur_roadtype, widget - WID_BROS_STATION_NE); } void OnClick(Point pt, int widget, int click_count) override @@ -1150,7 +1247,7 @@ static WindowDesc _tram_station_picker_desc( static void ShowRVStationPicker(Window *parent, RoadStopType rs) { - new BuildRoadStationWindow(_cur_roadtype == ROADTYPE_ROAD ? &_road_station_picker_desc : &_tram_station_picker_desc, parent, rs); + new BuildRoadStationWindow(RoadTypeIsRoad(_cur_roadtype) ? &_road_station_picker_desc : &_tram_station_picker_desc, parent, rs); } void InitializeRoadGui() @@ -1158,3 +1255,118 @@ void InitializeRoadGui() _road_depot_orientation = DIAGDIR_NW; _road_station_picker_orientation = DIAGDIR_NW; } + +/** + * I really don't know why rail_gui.cpp has this too, shouldn't be included in the other one? + */ +void InitializeRoadGUI() +{ + BuildRoadToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_ROAD)); + if (w != nullptr) w->ModifyRoadType(_cur_roadtype); +} + +DropDownList GetRoadTypeDropDownList(RoadTramTypes rtts, bool for_replacement, bool all_option) +{ + RoadTypes used_roadtypes; + RoadTypes avail_roadtypes; + + const Company *c = Company::Get(_local_company); + + /* Find the used roadtypes. */ + if (for_replacement) { + avail_roadtypes = GetCompanyRoadTypes(c->index, false); + used_roadtypes = GetRoadTypes(false); + } else { + avail_roadtypes = c->avail_roadtypes; + used_roadtypes = GetRoadTypes(true); + } + + /* Filter listed road types */ + if (!HasBit(rtts, RTT_ROAD)) used_roadtypes &= _roadtypes_type; + if (!HasBit(rtts, RTT_TRAM)) used_roadtypes &= ~_roadtypes_type; + + DropDownList list; + + if (all_option) { + list.emplace_back(new DropDownListStringItem(STR_REPLACE_ALL_ROADTYPE, INVALID_ROADTYPE, false)); + } + + Dimension d = { 0, 0 }; + RoadType rt; + /* Get largest icon size, to ensure text is aligned on each menu item. */ + if (!for_replacement) { + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); + } + } + + FOR_ALL_SORTED_ROADTYPES(rt) { + /* If it's not used ever, don't show it to the user. */ + if (!HasBit(used_roadtypes, rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + DropDownListParamStringItem *item; + if (for_replacement) { + item = new DropDownListParamStringItem(rti->strings.replace_text, rt, !HasBit(avail_roadtypes, rt)); + } else { + StringID str = rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING; + DropDownListIconItem *iconitem = new DropDownListIconItem(rti->gui_sprites.build_x_road, PAL_NONE, str, rt, !HasBit(avail_roadtypes, rt)); + iconitem->SetDimension(d); + item = iconitem; + } + item->SetParam(0, rti->strings.menu_text); + item->SetParam(1, rti->max_speed / 2); + list.emplace_back(item); + } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, INVALID_ROADTYPE, true)); + } + + return list; +} + +DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts) +{ + RoadTypes avail_roadtypes = GetRoadTypes(false); + avail_roadtypes = AddDateIntroducedRoadTypes(avail_roadtypes, _date); + RoadTypes used_roadtypes = GetRoadTypes(true); + + /* Filter listed road types */ + if (!HasBit(rtts, RTT_ROAD)) used_roadtypes &= _roadtypes_type; + if (!HasBit(rtts, RTT_TRAM)) used_roadtypes &= ~_roadtypes_type; + + DropDownList list; + + /* If it's not used ever, don't show it to the user. */ + Dimension d = { 0, 0 }; + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); + } + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + StringID str = rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING; + DropDownListIconItem *item = new DropDownListIconItem(rti->gui_sprites.build_x_road, PAL_NONE, str, rt, !HasBit(avail_roadtypes, rt)); + item->SetDimension(d); + item->SetParam(0, rti->strings.menu_text); + item->SetParam(1, rti->max_speed); + list.emplace_back(item); + } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, -1, true)); + } + + return list; +} diff --git a/src/road_gui.h b/src/road_gui.h index c56443c375..3f0b8f9006 100644 --- a/src/road_gui.h +++ b/src/road_gui.h @@ -15,9 +15,13 @@ #include "road_type.h" #include "tile_type.h" #include "direction_type.h" +#include "widgets/dropdown_type.h" struct Window *ShowBuildRoadToolbar(RoadType roadtype); -struct Window *ShowBuildRoadScenToolbar(); +struct Window *ShowBuildRoadScenToolbar(RoadType roadtype); void ConnectRoadToStructure(TileIndex tile, DiagDirection direction); +DropDownList GetRoadTypeDropDownList(RoadTramTypes rtts, bool for_replacement = false, bool all_option = false); +DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts); +void InitializeRoadGUI(); #endif /* ROAD_GUI_H */ diff --git a/src/road_internal.h b/src/road_internal.h index 8da909e94a..79782e3bba 100644 --- a/src/road_internal.h +++ b/src/road_internal.h @@ -17,8 +17,8 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb); -CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check = true); +CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadTramType rtt, DoCommandFlag flags, bool town_check = true); -void DrawRoadCatenary(const TileInfo *ti, RoadBits tram); +void DrawRoadCatenary(const TileInfo *ti); #endif /* ROAD_INTERNAL_H */ diff --git a/src/road_map.cpp b/src/road_map.cpp index 7d6a541fa8..96ff43ebe0 100644 --- a/src/road_map.cpp +++ b/src/road_map.cpp @@ -32,15 +32,15 @@ * @param straight_tunnel_bridge_entrance whether to return straight road bits for tunnels/bridges. * @return the road bits of the given tile */ -RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance) +RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance) { - if (!HasTileRoadType(tile, rt)) return ROAD_NONE; + if (!MayHaveRoad(tile) || !HasTileRoadType(tile, rtt)) return ROAD_NONE; switch (GetTileType(tile)) { case MP_ROAD: switch (GetRoadTileType(tile)) { default: - case ROAD_TILE_NORMAL: return GetRoadBits(tile, rt); + case ROAD_TILE_NORMAL: return GetRoadBits(tile, rtt); case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile); case ROAD_TILE_DEPOT: return DiagDirToRoadBits(GetRoadDepotDirection(tile)); } @@ -52,7 +52,7 @@ RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return ROAD_NONE; - if (IsRoadCustomBridgeHeadTile(tile)) return GetCustomBridgeHeadRoadBits(tile, rt); + if (IsRoadCustomBridgeHeadTile(tile)) return GetCustomBridgeHeadRoadBits(tile, rtt); return straight_tunnel_bridge_entrance ? AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) : DiagDirToRoadBits(ReverseDiagDir(GetTunnelBridgeDirection(tile))); diff --git a/src/road_map.h b/src/road_map.h index 7bc65b4fe1..1c3b9b6cc0 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -26,6 +26,28 @@ enum RoadTileType { ROAD_TILE_DEPOT, ///< Depot (one entrance) }; +/** + * Test whether a tile can have road/tram types. + * @param t Tile to query. + * @return true if tile can be queried about road/tram types. + */ +static inline bool MayHaveRoad(TileIndex t) +{ + switch (GetTileType(t)) { + case MP_ROAD: + return true; + + case MP_STATION: + return true; + + case MP_TUNNELBRIDGE: + return GB(_m[t].m5, 2, 2) == 1; + + default: + return false; + } +} + /** * Get the type of the road tile. * @param t Tile to query. @@ -108,26 +130,11 @@ static inline bool IsRoadDepotTile(TileIndex t) * @pre IsNormalRoad(t) * @return The present road bits for the road type. */ -static inline RoadBits GetRoadBits(TileIndex t, RoadType rt) +static inline RoadBits GetRoadBits(TileIndex t, RoadTramType rtt) { assert_tile(IsNormalRoad(t), t); - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: return (RoadBits)GB(_m[t].m5, 0, 4); - case ROADTYPE_TRAM: return (RoadBits)GB(_m[t].m3, 0, 4); - } -} - -/** - * Get all RoadBits set on a tile except from the given RoadType - * - * @param t The tile from which we want to get the RoadBits - * @param rt The RoadType which we exclude from the querry - * @return all set RoadBits of the tile which are not from the given RoadType - */ -static inline RoadBits GetOtherRoadBits(TileIndex t, RoadType rt) -{ - return GetRoadBits(t, rt == ROADTYPE_ROAD ? ROADTYPE_TRAM : ROADTYPE_ROAD); + if (rtt == RTT_TRAM) return (RoadBits)GB(_m[t].m3, 0, 4); + return (RoadBits)GB(_m[t].m5, 0, 4); } /** @@ -138,7 +145,7 @@ static inline RoadBits GetOtherRoadBits(TileIndex t, RoadType rt) */ static inline RoadBits GetAllRoadBits(TileIndex tile) { - return GetRoadBits(tile, ROADTYPE_ROAD) | GetRoadBits(tile, ROADTYPE_TRAM); + return GetRoadBits(tile, RTT_ROAD) | GetRoadBits(tile, RTT_TRAM); } /** @@ -148,96 +155,125 @@ static inline RoadBits GetAllRoadBits(TileIndex tile) * @param rt Road type. * @pre IsNormalRoad(t) */ -static inline void SetRoadBits(TileIndex t, RoadBits r, RoadType rt) +static inline void SetRoadBits(TileIndex t, RoadBits r, RoadTramType rtt) { assert_tile(IsNormalRoad(t), t); // XXX incomplete - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: SB(_m[t].m5, 0, 4, r); break; - case ROADTYPE_TRAM: SB(_m[t].m3, 0, 4, r); break; + if (rtt == RTT_TRAM) { + SB(_m[t].m3, 0, 4, r); + } else { + SB(_m[t].m5, 0, 4, r); } } +static inline RoadType GetRoadTypeRoad(TileIndex t) +{ + assert(MayHaveRoad(t)); + return (RoadType)GB(_m[t].m4, 0, 6); +} + +static inline RoadType GetRoadTypeTram(TileIndex t) +{ + assert(MayHaveRoad(t)); + return (RoadType)GB(_me[t].m8, 6, 6); +} + +static inline RoadType GetRoadType(TileIndex t, RoadTramType rtt) +{ + return (rtt == RTT_TRAM) ? GetRoadTypeTram(t) : GetRoadTypeRoad(t); +} + /** * Get the present road types of a tile. * @param t The tile to query. * @return Present road types. */ -static inline RoadTypes GetRoadTypes(TileIndex t) +static inline RoadTypes GetPresentRoadTypes(TileIndex t) { - return (RoadTypes)GB(_me[t].m7, 6, 2); + RoadTypes result = ROADTYPES_NONE; + if (MayHaveRoad(t)) { + if (GetRoadTypeRoad(t) != INVALID_ROADTYPE) SetBit(result, GetRoadTypeRoad(t)); + if (GetRoadTypeTram(t) != INVALID_ROADTYPE) SetBit(result, GetRoadTypeTram(t)); + } + return result; +} + +static inline bool HasRoadTypeRoad(TileIndex t) +{ + return GetRoadTypeRoad(t) != INVALID_ROADTYPE; +} + +static inline bool HasRoadTypeTram(TileIndex t) +{ + return GetRoadTypeTram(t) != INVALID_ROADTYPE; } /** - * Set the present road types of a tile. - * @param t The tile to change. - * @param rt The new road types. + * Check if a tile has a road or a tram road type. + * @param t The tile to check. + * @param tram True to check tram, false to check road. + * @return True if the tile has the specified road type. */ -static inline void SetRoadTypes(TileIndex t, RoadTypes rt) +static inline bool HasTileRoadType(TileIndex t, RoadTramType rtt) { - assert_tile(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE), t); - SB(_me[t].m7, 6, 2, rt); + return GetRoadType(t, rtt) != INVALID_ROADTYPE; } /** - * Check if a tile has a specific road type. + * Check if a tile has one of the specified road types. * @param t The tile to check. - * @param rt Road type to check. - * @return True if the tile has the specified road type. + * @param rts Allowed road types. + * @return True if the tile has one of the specified road types. */ -static inline bool HasTileRoadType(TileIndex t, RoadType rt) +static inline bool HasTileAnyRoadType(TileIndex t, RoadTypes rts) { - return HasBit(GetRoadTypes(t), rt); + if (!MayHaveRoad(t)) return false; + return (GetPresentRoadTypes(t) & rts); } /** * Get the owner of a specific road type. * @param t The tile to query. - * @param rt The road type to get the owner of. + * @param rtt RoadTramType. * @return Owner of the given road type. */ -static inline Owner GetRoadOwner(TileIndex t, RoadType rt) -{ - assert_tile(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE), t); - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: return (Owner)GB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5); - case ROADTYPE_TRAM: { - /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE - * to OWNER_TOWN makes it use one bit less */ - Owner o = (Owner)GB(_m[t].m3, 4, 4); - return o == OWNER_TOWN ? OWNER_NONE : o; - } - } +static inline Owner GetRoadOwner(TileIndex t, RoadTramType rtt) +{ + assert(MayHaveRoad(t)); + if (rtt == RTT_ROAD) return (Owner)GB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5); + + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + Owner o = (Owner)GB(_m[t].m3, 4, 4); + return o == OWNER_TOWN ? OWNER_NONE : o; } /** * Set the owner of a specific road type. * @param t The tile to change. - * @param rt The road type to change the owner of. + * @param rtt RoadTramType. * @param o New owner of the given road type. */ -static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) +static inline void SetRoadOwner(TileIndex t, RoadTramType rtt, Owner o) { - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: SB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5, o); break; - case ROADTYPE_TRAM: SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); break; + if (rtt == RTT_ROAD) { + SB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5, o); + } else { + SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); } } /** * Check if a specific road type is owned by an owner. * @param t The tile to query. - * @param rt The road type to compare the owner of. + * @param tram True to check tram, false to check road. * @param o Owner to compare with. * @pre HasTileRoadType(t, rt) * @return True if the road type is owned by the given owner. */ -static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o) +static inline bool IsRoadOwner(TileIndex t, RoadTramType rtt, Owner o) { - assert_tile(HasTileRoadType(t, rt), t); - return (GetRoadOwner(t, rt) == o); + assert_tile(HasTileRoadType(t, rtt), t); + return (GetRoadOwner(t, rtt) == o); } /** @@ -248,7 +284,7 @@ static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o) */ static inline bool HasTownOwnedRoad(TileIndex t) { - return HasTileRoadType(t, ROADTYPE_ROAD) && IsRoadOwner(t, ROADTYPE_ROAD, OWNER_TOWN); + return HasTileRoadType(t, RTT_ROAD) && IsRoadOwner(t, RTT_ROAD, OWNER_TOWN); } /** Which directions are disallowed ? */ @@ -545,29 +581,80 @@ static inline DiagDirection GetRoadDepotDirection(TileIndex t) } -RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance = false); +RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance = false); + +/** + * Set the road road type of a tile. + * @param t The tile to change. + * @param rt The road type to set. + */ +static inline void SetRoadTypeRoad(TileIndex t, RoadType rt) +{ + assert(MayHaveRoad(t)); + assert(rt == INVALID_ROADTYPE || RoadTypeIsRoad(rt)); + SB(_m[t].m4, 0, 6, rt); +} + +/** + * Set the tram road type of a tile. + * @param t The tile to change. + * @param rt The road type to set. + */ +static inline void SetRoadTypeTram(TileIndex t, RoadType rt) +{ + assert(MayHaveRoad(t)); + assert(rt == INVALID_ROADTYPE || RoadTypeIsTram(rt)); + SB(_me[t].m8, 6, 6, rt); +} + +/** + * Set the road type of a tile. + * @param t The tile to change. + * @param rtt Set road or tram type. + * @param rt The road type to set. + */ +static inline void SetRoadType(TileIndex t, RoadTramType rtt, RoadType rt) +{ + if (rtt == RTT_TRAM) { + SetRoadTypeTram(t, rt); + } else { + SetRoadTypeRoad(t, rt); + } +} +/** + * Set the present road types of a tile. + * @param t The tile to change. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. + */ +static inline void SetRoadTypes(TileIndex t, RoadType road_rt, RoadType tram_rt) +{ + SetRoadTypeRoad(t, road_rt); + SetRoadTypeTram(t, tram_rt); +} /** * Make a normal road tile. - * @param t Tile to make a normal road. - * @param bits Road bits to set for all present road types. - * @param rot New present road types. - * @param town Town ID if the road is a town-owned road. - * @param road New owner of road. - * @param tram New owner of tram tracks. + * @param t Tile to make a normal road. + * @param bits Road bits to set for all present road types. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. + * @param town Town ID if the road is a town-owned road. + * @param road New owner of road. + * @param tram New owner of tram tracks. */ -static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, TownID town, Owner road, Owner tram) +static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadType road_rt, RoadType tram_rt, TownID town, Owner road, Owner tram) { SetTileType(t, MP_ROAD); SetTileOwner(t, road); _m[t].m2 = town; - _m[t].m3 = (HasBit(rot, ROADTYPE_TRAM) ? bits : 0); - _m[t].m4 = 0; - _m[t].m5 = (HasBit(rot, ROADTYPE_ROAD) ? bits : 0) | ROAD_TILE_NORMAL << 6; + _m[t].m3 = (tram_rt != INVALID_ROADTYPE ? bits : 0); + _m[t].m5 = (road_rt != INVALID_ROADTYPE ? bits : 0) | ROAD_TILE_NORMAL << 6; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = rot << 6; - SetRoadOwner(t, ROADTYPE_TRAM, tram); + _me[t].m7 = 0; + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_TRAM, tram); } /** @@ -578,21 +665,23 @@ static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, Tow * @param rail New owner of the rail track. * @param roaddir Axis of the road. * @param rat New rail type. - * @param rot New present road types. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. * @param town Town ID if the road is a town-owned road. */ -static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadTypes rot, uint town) +static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadType road_rt, RoadType tram_rt, uint town) { SetTileType(t, MP_ROAD); SetTileOwner(t, rail); _m[t].m2 = town; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = ROAD_TILE_CROSSING << 6 | roaddir; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = rot << 6 | road; - _me[t].m8 = rat; - SetRoadOwner(t, ROADTYPE_TRAM, tram); + _me[t].m7 = road; + _me[t].m8 = INVALID_ROADTYPE << 6 | rat; + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_TRAM, tram); } /** @@ -600,7 +689,7 @@ static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner r * @param t Tile to make a level crossing. * @param owner New owner of the depot. * @param did New depot ID. - * @param dir Direction of the depot exit. + * @param dir Direction of the depot exit.* * @param rt Road type of the depot. */ static inline void MakeRoadDepot(TileIndex t, Owner owner, DepotID did, DiagDirection dir, RoadType rt) @@ -609,11 +698,13 @@ static inline void MakeRoadDepot(TileIndex t, Owner owner, DepotID did, DiagDire SetTileOwner(t, owner); _m[t].m2 = did; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = ROAD_TILE_DEPOT << 6 | dir; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = RoadTypeToRoadTypes(rt) << 6 | owner; - SetRoadOwner(t, ROADTYPE_TRAM, owner); + _me[t].m7 = owner; + _me[t].m8 = INVALID_ROADTYPE << 6; + SetRoadType(t, GetRoadTramType(rt), rt); + SetRoadOwner(t, RTT_TRAM, owner); } #endif /* ROAD_MAP_H */ diff --git a/src/road_type.h b/src/road_type.h index 491871a857..f695a00931 100644 --- a/src/road_type.h +++ b/src/road_type.h @@ -16,36 +16,37 @@ extern uint32 _road_layout_change_counter; +typedef uint32 RoadTypeLabel; + +static const RoadTypeLabel ROADTYPE_ROAD_LABEL = 'ROAD'; +static const RoadTypeLabel ROADTYPE_TRAM_LABEL = 'TRAM'; + /** * The different roadtypes we support * * @note currently only ROADTYPE_ROAD and ROADTYPE_TRAM are supported. */ enum RoadType { - ROADTYPE_BEGIN = 0, ///< Used for iterations - ROADTYPE_ROAD = 0, ///< Basic road type - ROADTYPE_TRAM = 1, ///< Trams - ROADTYPE_END, ///< Used for iterations - INVALID_ROADTYPE = 0xFF, ///< flag for invalid roadtype + ROADTYPE_BEGIN = 0, ///< Used for iterations + ROADTYPE_ROAD = 0, ///< Basic road type + ROADTYPE_TRAM = 1, ///< Trams + ROADTYPE_END = 63, ///< Used for iterations + INVALID_ROADTYPE = 63, ///< flag for invalid roadtype }; DECLARE_POSTFIX_INCREMENT(RoadType) -template <> struct EnumPropsT : MakeEnumPropsT {}; +template <> struct EnumPropsT : MakeEnumPropsT {}; /** - * The different roadtypes we support, but then a bitmask of them - * @note currently only roadtypes with ROADTYPE_ROAD and ROADTYPE_TRAM are supported. + * The different roadtypes we support, but then a bitmask of them. + * @note Must be treated as a uint64 type, narrowing it causes bit membership tests to give wrong results. */ -enum RoadTypes : byte { +enum RoadTypes : uint64 { ROADTYPES_NONE = 0, ///< No roadtypes ROADTYPES_ROAD = 1 << ROADTYPE_ROAD, ///< Road ROADTYPES_TRAM = 1 << ROADTYPE_TRAM, ///< Trams - ROADTYPES_ALL = ROADTYPES_ROAD | ROADTYPES_TRAM, ///< Road + trams - ROADTYPES_END, ///< Used for iterations? - INVALID_ROADTYPES = 0xFF, ///< Invalid roadtypes + INVALID_ROADTYPES = UINT64_MAX, ///< Invalid roadtypes }; DECLARE_ENUM_AS_BIT_SET(RoadTypes) -template <> struct EnumPropsT : MakeEnumPropsT {}; - /** * Enumeration for the road parts on a tile. diff --git a/src/roadstop.cpp b/src/roadstop.cpp index acefa8362b..694e33f0dd 100644 --- a/src/roadstop.cpp +++ b/src/roadstop.cpp @@ -45,7 +45,7 @@ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const { for (RoadStop *rs = this->next; rs != nullptr; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ - if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; + if (!HasTileAnyRoadType(rs->xy, v->compatible_roadtypes)) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; diff --git a/src/roadveh.h b/src/roadveh.h index 710add4538..9ea034a845 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -16,7 +16,8 @@ #include "engine_base.h" #include "cargotype.h" #include "track_func.h" -#include "road_type.h" +#include "road.h" +#include "road_map.h" #include "newgrf_engine.h" #include @@ -116,8 +117,8 @@ struct RoadVehicle FINAL : public GroundVehicle { uint16 crashed_ctr; ///< Animation counter when the vehicle has crashed. @see RoadVehIsCrashed byte reverse_ctr; - RoadType roadtype; - RoadTypes compatible_roadtypes; + RoadType roadtype; //!< Roadtype of this vehicle. + RoadTypes compatible_roadtypes; //!< Roadtypes this consist is powered on. byte critical_breakdown_count; ///< Counter for the number of critical breakdowns since last service @@ -280,7 +281,7 @@ protected: // These functions should not be called outside acceleration code. { /* Trams have a slightly greater friction coefficient than trains. * The rest of road vehicles have bigger values. */ - uint32 coeff = (this->roadtype == ROADTYPE_TRAM) ? 40 : 75; + uint32 coeff = RoadTypeIsTram(this->roadtype) ? 40 : 75; /* The friction coefficient increases with speed in a way that * it doubles at 128 km/h, triples at 256 km/h and so on. */ return coeff * (128 + this->GetCurrentSpeed()) / 128; @@ -310,7 +311,7 @@ protected: // These functions should not be called outside acceleration code. */ inline uint16 GetMaxTrackSpeed() const { - return 0; + return GetRoadTypeInfo(GetRoadType(this->tile, GetRoadTramType(this->roadtype)))->max_speed; } /** @@ -319,7 +320,7 @@ protected: // These functions should not be called outside acceleration code. */ inline bool TileMayHaveSlopedTrack() const { - TrackStatus ts = GetTileTrackStatus(this->tile, TRANSPORT_ROAD, this->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(this->tile, TRANSPORT_ROAD, GetRoadTramType(this->roadtype)); TrackBits trackbits = TrackStatusToTrackBits(ts); return trackbits == TRACK_BIT_X || trackbits == TRACK_BIT_Y; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 746b5786ce..7497ec09b7 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -265,7 +265,10 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length) */ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { - if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE); + /* Check that the vehicle can drive on the road in question */ + RoadType rt = e->u.road.roadtype; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + if (!HasTileAnyRoadType(tile, rti->powered_roadtypes)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE); if (flags & DC_EXEC) { const RoadVehicleInfo *rvi = &e->u.road; @@ -310,8 +313,8 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->random_bits = VehicleRandomBits(); v->SetFrontEngine(); - v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype); + v->roadtype = rt; + v->compatible_roadtypes = rti->powered_roadtypes; v->gcache.cached_veh_length = VEHICLE_LENGTH; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); @@ -449,6 +452,8 @@ int RoadVehicle::GetEffectiveMaxSpeed() const { int max_speed = this->vcache.cached_max_speed; + if (this->critical_breakdown_count == 0) return max_speed; + for (uint i = 0; i < this->critical_breakdown_count; i++) { max_speed = min(max_speed - (max_speed / 3) + 1, max_speed); } @@ -469,10 +474,10 @@ inline int RoadVehicle::GetCurrentMaxSpeed() const for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) { if (_settings_game.vehicle.roadveh_acceleration_model == AM_REALISTIC) { if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) { - max_speed = this->vcache.cached_max_speed / 2; + max_speed = this->gcache.cached_max_track_speed / 2; break; } else if ((u->direction & 1) == 0) { - max_speed = this->vcache.cached_max_speed * 3 / 4; + max_speed = this->gcache.cached_max_track_speed * 3 / 4; } } @@ -737,7 +742,7 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st) st->had_vehicle_of_type |= HVOT_BUS; SetDParam(0, st->index); AddVehicleNewsItem( - v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, + RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index @@ -751,7 +756,7 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st) st->had_vehicle_of_type |= HVOT_TRUCK; SetDParam(0, st->index); AddVehicleNewsItem( - v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, + RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index @@ -829,7 +834,8 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) */ static bool CheckRoadBlockedForOvertaking(OvertakeData *od) { - TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes); + if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true; + TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype)); TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits); @@ -849,7 +855,7 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) od.u = u; /* Trams can't overtake other trams */ - if (v->roadtype == ROADTYPE_TRAM) return; + if (RoadTypeIsTram(v->roadtype)) return; /* Don't overtake in stations */ if (IsTileType(u->tile, MP_STATION)) return; @@ -923,7 +929,7 @@ static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z) v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10% } else { uint16 spd = v->cur_speed + 2; - if (spd <= v->vcache.cached_max_speed) v->cur_speed = spd; + if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd; } } @@ -952,12 +958,12 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection Trackdir best_track; bool path_found = true; - TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype)); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts); if (IsTileType(tile, MP_ROAD)) { - if (IsRoadDepot(tile) && (!IsInfraTileUsageAllowed(VEH_ROAD, v->owner, tile) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) { + if (IsRoadDepot(tile) && (!IsInfraTileUsageAllowed(VEH_ROAD, v->owner, tile) || GetRoadDepotDirection(tile) == enterdir)) { /* Road depot owned by another company or with the wrong orientation */ trackdirs = TRACKDIR_BIT_NONE; } @@ -1000,10 +1006,10 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection if (v->reverse_ctr != 0) { bool reverse = true; - if (v->roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(v->roadtype)) { /* Trams may only reverse on a tile if it contains at least the straight * trackbits or when it is a valid turning tile (i.e. one roadbit) */ - RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = GetAnyRoadBits(tile, RTT_TRAM); RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir)); reverse = ((rb & straight) == straight) || (rb == DiagDirToRoadBits(enterdir)); @@ -1087,7 +1093,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) v->direction = DiagDirToDir(dir); Trackdir tdir = DiagDirToDiagTrackdir(dir); - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir]; int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF); int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF); @@ -1183,7 +1189,7 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl }; RoadBits required = required_roadbits[dir & 0x07]; - if ((required & GetAnyRoadBits(tile, v->roadtype, false)) == ROAD_NONE) { + if ((required & GetAnyRoadBits(tile, GetRoadTramType(v->roadtype), false)) == ROAD_NONE) { dir = INVALID_TRACKDIR; } @@ -1194,15 +1200,16 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl * Can a tram track build without destruction on the given tile? * @param c the company that would be building the tram tracks * @param t the tile to build on. + * @param rt the tram type to build. * @param r the road bits needed. * @return true when a track track can be build on 't' */ -static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r) +static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r) { /* The 'current' company is not necessarily the owner of the vehicle. */ Backup cur_company(_current_company, c, FILE_LINE); - CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NO_WATER, CMD_BUILD_ROAD); + CommandCost ret = DoCommand(t, rt << 4 | r, 0, DC_NO_WATER, CMD_BUILD_ROAD); cur_company.Restore(); return ret.Succeeded(); @@ -1275,7 +1282,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) /* Get move position data for next frame. * For a drive-through road stop use 'straight road' move data. * In this case v->state is masked to give the road stop entry direction. */ - RoadDriveEntry rd = _road_drive_data[v->roadtype][( + RoadDriveEntry rd = _road_drive_data[GetRoadTramType(v->roadtype)][( (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1]; @@ -1286,7 +1293,11 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) if (v->IsFrontEngine()) { /* If this is the front engine, look for the right path. */ - dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3)); + if (HasTileAnyRoadType(tile, v->compatible_roadtypes)) { + dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3)); + } else { + dir = _road_reverse_table[(DiagDirection)(rd.x & 3)]; + } } else if (no_advance_tile) { /* Follow previous vehicle out of custom bridge wormhole */ dir = (Trackdir) prev->state; @@ -1311,7 +1322,7 @@ again: } /* Turning around */ - if (v->roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(v->roadtype)) { /* Determine the road bits the tram needs to be able to turn around * using the 'big' corner loop. */ RoadBits needed; @@ -1324,9 +1335,9 @@ again: } auto tile_turn_ok = [&]() -> bool { if (IsNormalRoadTile(tile)) { - return !HasRoadWorks(tile) && (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE; + return !HasRoadWorks(tile) && HasTileAnyRoadType(tile, v->compatible_roadtypes) && (needed & GetRoadBits(tile, RTT_TRAM)) != ROAD_NONE; } else if (IsRoadCustomBridgeHeadTile(tile)) { - return (needed & GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE; + return HasTileAnyRoadType(tile, v->compatible_roadtypes) && (needed & GetCustomBridgeHeadRoadBits(tile, RTT_TRAM)) != ROAD_NONE; } else { return false; } @@ -1342,7 +1353,7 @@ again: * going to cause the tram to split up. * - Or the front of the tram can drive over the next tile. */ - } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) { + } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, v->roadtype, needed) || ((~needed & GetAnyRoadBits(v->tile, RTT_TRAM, false)) == ROAD_NONE)) { /* * Taking the 'small' corner for trams only happens when: * - We are not the from vehicle of an articulated tram. @@ -1370,7 +1381,7 @@ again: } /* Get position data for first frame on the new tile */ - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking]; int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x; int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y; @@ -1423,9 +1434,18 @@ again: if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { v->cur_image_valid_dir = INVALID_DIR; + TileIndex old_tile = v->tile; + v->tile = tile; v->state = (byte)dir; v->frame = start_frame; + RoadTramType rtt = GetRoadTramType(v->roadtype); + if (GetRoadType(old_tile, rtt) != GetRoadType(tile, rtt)) { + if (v->IsFrontEngine()) { + RoadVehUpdateCache(v); + } + v->First()->CargoChanged(); + } } if (new_dir != v->direction) { v->direction = new_dir; @@ -1443,7 +1463,7 @@ again: Trackdir dir; uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME; - if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false))) { + if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, RTT_TRAM, false))) { /* * The tram is turning around with one tram 'roadbit'. This means that * it is using the 'big' corner 'drive data'. However, to support the @@ -1475,7 +1495,7 @@ again: return false; } - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir]; int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x; int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y; @@ -1584,7 +1604,7 @@ again: TileIndex next_tile = TileAddByDir(v->tile, v->direction); /* Check if next inline bay is free and has compatible road. */ - if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) { + if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && HasTileAnyRoadType(next_tile, v->compatible_roadtypes)) { v->frame++; v->x_pos = x; v->y_pos = y; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 23e23f159a..653431acba 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -297,6 +297,12 @@ static void InitializeWindowsAndCaches() (*it)->tile = t->xy; } } + RoadVehicle *rv; + FOR_ALL_ROADVEHICLES(rv) { + if (rv->IsFrontEngine()) { + rv->CargoChanged(); + } + } RecomputePrices(); @@ -518,8 +524,19 @@ static void FixOwnerOfRailTrack(TileIndex t) if (IsLevelCrossingTile(t)) { /* else change the crossing to normal road (road vehicles won't care) */ - MakeRoadNormal(t, GetCrossingRoadBits(t), GetRoadTypes(t), GetTownIndex(t), - GetRoadOwner(t, ROADTYPE_ROAD), GetRoadOwner(t, ROADTYPE_TRAM)); + Owner road = GetRoadOwner(t, RTT_ROAD); + Owner tram = GetRoadOwner(t, RTT_TRAM); + RoadBits bits = GetCrossingRoadBits(t); + bool hasroad = HasBit(_me[t].m7, 6); + bool hastram = HasBit(_me[t].m7, 7); + + /* MakeRoadNormal */ + SetTileType(t, MP_ROAD); + SetTileOwner(t, road); + _m[t].m3 = (hasroad ? bits : 0); + _m[t].m5 = (hastram ? bits : 0) | ROAD_TILE_NORMAL << 6; + SB(_me[t].m6, 2, 4, 0); + SetRoadOwner(t, RTT_TRAM, tram); return; } @@ -1217,18 +1234,18 @@ bool AfterLoadGame() break; case ROAD_TILE_DEPOT: break; } - SetRoadTypes(t, ROADTYPES_ROAD); + SB(_me[t].m7, 6, 2, 1); // Set pre-NRT road type bits for conversion later. break; case MP_STATION: - if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); + if (IsRoadStop(t)) SB(_me[t].m7, 6, 2, 1); break; case MP_TUNNELBRIDGE: /* Middle part of "old" bridges */ if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { - SetRoadTypes(t, ROADTYPES_ROAD); + SB(_me[t].m7, 6, 2, 1); // Set pre-NRT road type bits for conversion later. } break; @@ -1244,7 +1261,7 @@ bool AfterLoadGame() for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_ROAD: - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_me[t].m7, 5, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_me[t].m7, 5, 3)); SB(_me[t].m7, 5, 1, GB(_m[t].m3, 7, 1)); // snow/desert switch (GetRoadTileType(t)) { default: SlErrorCorrupt("Invalid road tile type"); @@ -1277,7 +1294,7 @@ bool AfterLoadGame() case MP_STATION: if (!IsRoadStop(t)) break; - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_m[t].m3, 0, 3)); SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwner(t)); SB(_m[t].m3, 4, 4, _m[t].m1); _m[t].m4 = 0; @@ -1286,7 +1303,7 @@ bool AfterLoadGame() case MP_TUNNELBRIDGE: if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_m[t].m3, 0, 3)); Owner o = GetTileOwner(t); SB(_me[t].m7, 0, 5, o); // road owner @@ -1362,13 +1379,14 @@ bool AfterLoadGame() } else { TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; - MakeRoadNormal( - t, - axis == AXIS_X ? ROAD_Y : ROAD_X, - ROADTYPES_ROAD, - town, - GetTileOwner(t), OWNER_NONE - ); + /* MakeRoadNormal */ + SetTileType(t, MP_ROAD); + _m[t].m2 = town; + _m[t].m3 = 0; + _m[t].m5 = (axis == AXIS_X ? ROAD_Y : ROAD_X) | ROAD_TILE_NORMAL << 6; + SB(_me[t].m6, 2, 4, 0); + _me[t].m7 = 1 << 6; + SetRoadOwner(t, RTT_TRAM, OWNER_NONE); } } else { if (GB(_m[t].m5, 3, 2) == 0) { @@ -1423,6 +1441,35 @@ bool AfterLoadGame() } } + if (IsSavegameVersionBefore(SLV_ROAD_TYPES)) { + /* Add road subtypes */ + for (TileIndex t = 0; t < map_size; t++) { + bool has_road = false; + switch (GetTileType(t)) { + case MP_ROAD: + has_road = true; + break; + case MP_STATION: + has_road = IsRoadStop(t); + break; + case MP_TUNNELBRIDGE: + has_road = GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD; + break; + default: + break; + } + + if (has_road) { + RoadType road_rt = HasBit(_me[t].m7, 6) ? ROADTYPE_ROAD : INVALID_ROADTYPE; + RoadType tram_rt = HasBit(_me[t].m7, 7) ? ROADTYPE_TRAM : INVALID_ROADTYPE; + + assert(road_rt != INVALID_ROADTYPE || tram_rt != INVALID_ROADTYPE); + SetRoadTypes(t, road_rt, tram_rt); + SB(_me[t].m7, 6, 2, 0); // Clear pre-NRT road type bits. + } + } + } + if (SlXvIsFeatureMissing(XSLFI_DUAL_RAIL_TYPES)) { /* Introduced dual rail types. */ for (TileIndex t = 0; t < map_size; t++) { @@ -1580,7 +1627,7 @@ bool AfterLoadGame() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); } if (!IsSavegameVersionBefore(SLV_27)) AfterLoadStations(); @@ -2049,10 +2096,10 @@ bool AfterLoadGame() } } else if (IsTileType(t, MP_ROAD)) { /* works for all RoadTileType */ - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* update even non-existing road types to update tile owner too */ - Owner o = GetRoadOwner(t, rt); - if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rt, OWNER_NONE); + Owner o = GetRoadOwner(t, rtt); + if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rtt, OWNER_NONE); } if (IsLevelCrossing(t)) { if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); @@ -2902,7 +2949,7 @@ bool AfterLoadGame() if (rv->state == RVSB_IN_DEPOT || rv->state == RVSB_WORMHOLE) break; - TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, rv->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, GetRoadTramType(rv->roadtype)); TrackBits trackbits = TrackStatusToTrackBits(ts); /* Only X/Y tracks can be sloped. */ @@ -3177,8 +3224,8 @@ bool AfterLoadGame() for (TileIndex t = 0; t < map_size; t++) { if (!IsStandardRoadStopTile(t)) continue; Owner o = GetTileOwner(t); - SetRoadOwner(t, ROADTYPE_ROAD, o); - SetRoadOwner(t, ROADTYPE_TRAM, o); + SetRoadOwner(t, RTT_ROAD, o); + SetRoadOwner(t, RTT_TRAM, o); } } diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index f03239e596..8cf5207d5e 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -136,11 +136,12 @@ void AfterLoadCompanyStats() } /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rt)); + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + if (rt == INVALID_ROADTYPE) continue; + c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rtt)); /* A level crossings and depots have two road bits. */ - if (c != nullptr) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rt)) : 2; + if (c != nullptr) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rtt)) : 2; } break; } @@ -158,9 +159,10 @@ void AfterLoadCompanyStats() case STATION_BUS: case STATION_TRUCK: { /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - c = Company::GetIfValid(GetRoadOwner(tile, rt)); + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + if (rt == INVALID_ROADTYPE) continue; + c = Company::GetIfValid(GetRoadOwner(tile, rtt)); if (c != nullptr) c->infrastructure.road[rt] += 2; // A road stop has two road bits. } break; diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index e03b1dd407..04aa762e86 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -301,6 +301,7 @@ enum SaveLoadVersion : uint16 { SLV_ROADVEH_PATH_CACHE, ///< 211 PR#7261 Add path cache for road vehicles. SLV_REMOVE_OPF, ///< 212 PR#7245 Remove OPF. SLV_TREES_WATER_CLASS, ///< 213 PR#7405 WaterClass update for tree tiles. + SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types. SL_MAX_VERSION, ///< Highest possible saveload version diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 25469253ba..23a10b8a98 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -423,6 +423,14 @@ void AfterLoadVehicles(bool part_of_load) RoadVehicle *rv = RoadVehicle::From(v); if (rv->IsFrontEngine()) { rv->gcache.last_speed = rv->cur_speed; // update displayed road vehicle speed + + rv->roadtype = Engine::Get(rv->engine_type)->u.road.roadtype; + rv->compatible_roadtypes = GetRoadTypeInfo(rv->roadtype)->powered_roadtypes; + for (RoadVehicle *u = rv; u != nullptr; u = u->Next()) { + u->roadtype = rv->roadtype; + u->compatible_roadtypes = rv->compatible_roadtypes; + } + RoadVehUpdateCache(rv); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { rv->CargoChanged(); @@ -461,13 +469,7 @@ void AfterLoadVehicles(bool part_of_load) FOR_ALL_VEHICLES(v) { switch (v->type) { - case VEH_ROAD: { - RoadVehicle *rv = RoadVehicle::From(v); - rv->roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - rv->compatible_roadtypes = RoadTypeToRoadTypes(rv->roadtype); - FALLTHROUGH; - } - + case VEH_ROAD: case VEH_TRAIN: case VEH_SHIP: v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq); diff --git a/src/script/api/ai/ai_engine.hpp.sq b/src/script/api/ai/ai_engine.hpp.sq index 6dbde29099..b10e7e34f7 100644 --- a/src/script/api/ai/ai_engine.hpp.sq +++ b/src/script/api/ai/ai_engine.hpp.sq @@ -41,6 +41,8 @@ void SQAIEngine_Register(Squirrel *engine) SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); + SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRoad, "CanRunOnRoad", 3, ".ii"); + SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRoad, "HasPowerOnRoad", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); diff --git a/src/script/api/ai/ai_rail.hpp.sq b/src/script/api/ai/ai_rail.hpp.sq index ba9d7e6564..d7e421669f 100644 --- a/src/script/api/ai/ai_rail.hpp.sq +++ b/src/script/api/ai/ai_rail.hpp.sq @@ -56,7 +56,7 @@ void SQAIRail_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); - ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_RAIL, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); diff --git a/src/script/api/ai/ai_road.hpp.sq b/src/script/api/ai/ai_road.hpp.sq index 3da4607c90..7e91fb2682 100644 --- a/src/script/api/ai/ai_road.hpp.sq +++ b/src/script/api/ai/ai_road.hpp.sq @@ -26,9 +26,13 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_ROAD, "ROADTRAMTYPES_ROAD"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_TRAM, "ROADTRAMTYPES_TRAM"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); @@ -40,12 +44,19 @@ void SQAIRoad_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_ROAD, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_TRAMWAY, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_INCOMPATIBLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetName, "GetName", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); @@ -54,6 +65,9 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehCanRunOnRoad, "RoadVehCanRunOnRoad", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehHasPowerOnRoad, "RoadVehHasPowerOnRoad", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::ConvertRoadType, "ConvertRoadType", 4, ".iii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); @@ -74,6 +88,8 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadTramType, "GetRoadTramType", 2, ".i"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQAIRoad.PostRegister(engine); diff --git a/src/script/api/ai/ai_roadtypelist.hpp.sq b/src/script/api/ai/ai_roadtypelist.hpp.sq new file mode 100644 index 0000000000..cbe316f8d2 --- /dev/null +++ b/src/script/api/ai/ai_roadtypelist.hpp.sq @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" +#include "../template/template_roadtypelist.hpp.sq" + + +template <> const char *GetClassName() { return "AIRoadTypeList"; } + +void SQAIRoadTypeList_Register(Squirrel *engine) +{ + DefSQClass SQAIRoadTypeList("AIRoadTypeList"); + SQAIRoadTypeList.PreRegister(engine, "AIList"); + SQAIRoadTypeList.AddConstructor(engine, "xi"); + + SQAIRoadTypeList.PostRegister(engine); +} diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index c6a790f865..5aacf8e8c8 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -26,6 +26,14 @@ * \li AIGroup::GetSecondaryColour * \li AIVehicle::BuildVehicleWithRefit * \li AIVehicle::GetBuildWithRefitCapacity + * \li AIRoad::GetName + * \li AIRoad::RoadVehCanRunOnRoad + * \li AIRoad::RoadVehHasPowerOnRoad + * \li AIRoad::ConvertRoadType + * \li AIRoad::GetMaxSpeed + * \li AIEngine::CanRunOnRoad + * \li AIEngine::HasPowerOnRoad + * \li AIRoadTypeList::RoadTypeList * * \b 1.9.0 * @@ -46,6 +54,9 @@ * * No changes * + * API additions: + * \li AIRoad::ERR_ROADTYPE_DISALLOWS_CROSSING + * * \b 1.7.0 - 1.7.2 * * No changes diff --git a/src/script/api/game/game_engine.hpp.sq b/src/script/api/game/game_engine.hpp.sq index 4881755473..67153b1d9e 100644 --- a/src/script/api/game/game_engine.hpp.sq +++ b/src/script/api/game/game_engine.hpp.sq @@ -41,6 +41,8 @@ void SQGSEngine_Register(Squirrel *engine) SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); + SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRoad, "CanRunOnRoad", 3, ".ii"); + SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRoad, "HasPowerOnRoad", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); diff --git a/src/script/api/game/game_rail.hpp.sq b/src/script/api/game/game_rail.hpp.sq index c057360300..f145e84818 100644 --- a/src/script/api/game/game_rail.hpp.sq +++ b/src/script/api/game/game_rail.hpp.sq @@ -56,7 +56,7 @@ void SQGSRail_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); - ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_RAIL, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); diff --git a/src/script/api/game/game_road.hpp.sq b/src/script/api/game/game_road.hpp.sq index 51da4144eb..725e24bf12 100644 --- a/src/script/api/game/game_road.hpp.sq +++ b/src/script/api/game/game_road.hpp.sq @@ -26,9 +26,13 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_ROAD, "ROADTRAMTYPES_ROAD"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_TRAM, "ROADTRAMTYPES_TRAM"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); @@ -40,12 +44,19 @@ void SQGSRoad_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_ROAD, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_TRAMWAY, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_INCOMPATIBLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetName, "GetName", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); @@ -54,6 +65,9 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehCanRunOnRoad, "RoadVehCanRunOnRoad", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehHasPowerOnRoad, "RoadVehHasPowerOnRoad", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::ConvertRoadType, "ConvertRoadType", 4, ".iii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); @@ -74,6 +88,8 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadTramType, "GetRoadTramType", 2, ".i"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQGSRoad.PostRegister(engine); diff --git a/src/script/api/game/game_roadtypelist.hpp.sq b/src/script/api/game/game_roadtypelist.hpp.sq new file mode 100644 index 0000000000..f61adaa8fa --- /dev/null +++ b/src/script/api/game/game_roadtypelist.hpp.sq @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" +#include "../template/template_roadtypelist.hpp.sq" + + +template <> const char *GetClassName() { return "GSRoadTypeList"; } + +void SQGSRoadTypeList_Register(Squirrel *engine) +{ + DefSQClass SQGSRoadTypeList("GSRoadTypeList"); + SQGSRoadTypeList.PreRegister(engine, "GSList"); + SQGSRoadTypeList.AddConstructor(engine, "xi"); + + SQGSRoadTypeList.PostRegister(engine); +} diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 143caec27e..19bf111121 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -229,8 +229,8 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RAIL_ROAD_TYPE_DROPDOWN, "WID_RV_RAIL_ROAD_TYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, "WID_RV_TRAIN_ENGINEWAGON_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); @@ -387,6 +387,8 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TRAM_DESC, "WID_CI_TRAM_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TRAM_COUNT, "WID_CI_TRAM_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); @@ -999,6 +1001,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_CAPTION, "WID_ROT_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); @@ -1010,6 +1013,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_CONVERT_ROAD, "WID_ROT_CONVERT_ROAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); @@ -1218,6 +1222,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_BUILDING_TOOLS_START, "WID_TN_BUILDING_TOOLS_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAMS, "WID_TN_TRAMS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); @@ -1241,6 +1246,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TRAMS, "WID_TE_TRAMS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 04bc893c18..3befcaf97a 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -22,6 +22,11 @@ * API additions: * \li GSVehicle::BuildVehicleWithRefit * \li GSVehicle::GetBuildWithRefitCapacity + * \li GSRoad::GetName + * \li GSRoad::RoadVehCanRunOnRoad + * \li GSRoad::RoadVehHasPowerOnRoad + * \li GSRoad::ConvertRoadType + * \li GSRoad::GetMaxSpeed * * \b 1.9.0 * @@ -42,6 +47,9 @@ * * No changes * + * API additions: + * \li GSRoad::ERR_ROADTYPE_DISALLOWS_CROSSING + * * \b 1.7.0 - 1.7.2 * * No changes diff --git a/src/script/api/script_bridge.cpp b/src/script/api/script_bridge.cpp index d30b154c08..53164cee2e 100644 --- a/src/script/api/script_bridge.cpp +++ b/src/script/api/script_bridge.cpp @@ -83,7 +83,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) switch (vehicle_type) { case ScriptVehicle::VT_ROAD: type |= (TRANSPORT_ROAD << 15); - type |= (::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()) << 8); + type |= (ScriptRoad::GetCurrentRoadType() << 8); break; case ScriptVehicle::VT_RAIL: type |= (TRANSPORT_RAIL << 15); @@ -114,7 +114,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); - return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4) | (1 << 8), 0, CMD_BUILD_ROAD, nullptr, &::_DoCommandReturnBuildBridge2); + return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptRoad::GetCurrentRoadType() << 4) | (1 << 13), 0, CMD_BUILD_ROAD, nullptr, &::_DoCommandReturnBuildBridge2); } /* static */ bool ScriptBridge::_BuildBridgeRoad2() @@ -126,7 +126,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); - return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptObject::GetRoadType() << 4) | (1 << 8), 0, CMD_BUILD_ROAD); + return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptRoad::GetCurrentRoadType() << 4) | (1 << 13), 0, CMD_BUILD_ROAD); } /* static */ bool ScriptBridge::RemoveBridge(TileIndex tile) diff --git a/src/script/api/script_engine.cpp b/src/script/api/script_engine.cpp index dfd15bee49..88f55226ea 100644 --- a/src/script/api/script_engine.cpp +++ b/src/script/api/script_engine.cpp @@ -15,6 +15,7 @@ #include "../../company_base.h" #include "../../strings_func.h" #include "../../rail.h" +#include "../../road.h" #include "../../engine_base.h" #include "../../engine_func.h" #include "../../articulated_vehicles.h" @@ -219,12 +220,26 @@ return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type); } +/* static */ bool ScriptEngine::CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type) +{ + return HasPowerOnRoad(engine_id, road_type); +} + +/* static */ bool ScriptEngine::HasPowerOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type) +{ + if (!IsValidEngine(engine_id)) return false; + if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return false; + if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false; + + return ::HasPowerOnRoad((::RoadType)::RoadVehInfo(engine_id)->roadtype, (::RoadType)road_type); +} + /* static */ ScriptRoad::RoadType ScriptEngine::GetRoadType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; - return HasBit(::EngInfo(engine_id)->misc_flags, EF_ROAD_TRAM) ? ScriptRoad::ROADTYPE_TRAM : ScriptRoad::ROADTYPE_ROAD; + return (ScriptRoad::RoadType)(uint)::RoadVehInfo(engine_id)->roadtype; } /* static */ ScriptRail::RailType ScriptEngine::GetRailType(EngineID engine_id) diff --git a/src/script/api/script_engine.hpp b/src/script/api/script_engine.hpp index 173377742d..b08b6f64b4 100644 --- a/src/script/api/script_engine.hpp +++ b/src/script/api/script_engine.hpp @@ -217,6 +217,28 @@ public: */ static bool HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type); + /** + * Check if a road vehicle can run on a RoadType. + * @param engine_id The engine to check. + * @param road_type Another RoadType. + * @pre IsValidEngine(engine_id). + * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD. + * @pre ScriptRoad::IsRoadTypeAvailable(road_type). + * @return Whether an engine of type 'engine_id' can run on 'road_type'. + */ + static bool CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type); + + /** + * Check if a road vehicle has power on a RoadType. + * @param engine_id The engine to check. + * @param road_type Another RoadType. + * @pre IsValidEngine(engine_id). + * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD. + * @pre ScriptRoad::IsRoadTypeAvailable(road_type). + * @return Whether an engine of type 'engine_id' has power on 'road_type'. + */ + static bool HasPowerOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type); + /** * Get the RoadType of the engine. * @param engine_id The engine to get the RoadType of. diff --git a/src/script/api/script_infrastructure.cpp b/src/script/api/script_infrastructure.cpp index d7da2747e1..35febbd58a 100644 --- a/src/script/api/script_infrastructure.cpp +++ b/src/script/api/script_infrastructure.cpp @@ -90,7 +90,8 @@ company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RoadType)roadtype >= ROADTYPE_END || !_settings_game.economy.infrastructure_maintenance) return 0; - return ::RoadMaintenanceCost((::RoadType)roadtype, ::Company::Get((::CompanyID)company)->infrastructure.road[roadtype]); + const ::Company *c = ::Company::Get((::CompanyID)company); + return ::RoadMaintenanceCost((::RoadType)roadtype, c->infrastructure.road[roadtype], RoadTypeIsRoad((::RoadType)roadtype) ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal()); } /* static */ Money ScriptInfrastructure::GetMonthlyInfrastructureCosts(ScriptCompany::CompanyID company, Infrastructure infra_type) @@ -114,8 +115,9 @@ case INFRASTRUCTURE_ROAD: { Money cost; + uint32 road_total = c->infrastructure.GetRoadTotal(); for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) { - cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt]); + cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total); } return cost; } diff --git a/src/script/api/script_rail.hpp b/src/script/api/script_rail.hpp index 7e2a59e7f7..d52a7bfc46 100644 --- a/src/script/api/script_rail.hpp +++ b/src/script/api/script_rail.hpp @@ -36,7 +36,7 @@ public: ERR_UNSUITABLE_TRACK, // [STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, STR_ERROR_THERE_ARE_NO_SIGNALS, STR_ERROR_THERE_IS_NO_STATION] /** This railtype cannot have crossings */ - ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED] + ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED_RAIL] }; /** diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 74899f8bb3..afa4b28d37 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -23,6 +23,13 @@ return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK; } +/* static */ char *ScriptRoad::GetName(RoadType road_type) +{ + if (!IsRoadTypeAvailable(road_type)) return nullptr; + + return GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name); +} + /* static */ bool ScriptRoad::IsRoadTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; @@ -37,7 +44,7 @@ if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT && - (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsRoadStationTile(TileIndex tile) @@ -45,7 +52,7 @@ if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - return ::IsRoadStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + return ::IsRoadStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile) @@ -53,12 +60,12 @@ if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - return ::IsDriveThroughStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + return ::IsDriveThroughStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type) { - return ::IsValidRoadType((::RoadType)road_type) && ::HasRoadTypesAvail(ScriptObject::GetCompany(), ::RoadTypeToRoadTypes((::RoadType)road_type)); + return (::RoadType)road_type < ROADTYPE_END && ::HasRoadTypeAvail(ScriptObject::GetCompany(), (::RoadType)road_type); } /* static */ ScriptRoad::RoadType ScriptRoad::GetCurrentRoadType() @@ -73,11 +80,24 @@ ScriptObject::SetRoadType((::RoadType)road_type); } +/* static */ bool ScriptRoad::RoadVehCanRunOnRoad(RoadType engine_road_type, RoadType road_road_type) +{ + return RoadVehHasPowerOnRoad(engine_road_type, road_road_type); +} + +/* static */ bool ScriptRoad::RoadVehHasPowerOnRoad(RoadType engine_road_type, RoadType road_road_type) +{ + if (!IsRoadTypeAvailable(engine_road_type)) return false; + if (!IsRoadTypeAvailable(road_road_type)) return false; + + return ::HasPowerOnRoad((::RoadType)engine_road_type, (::RoadType)road_road_type); +} + /* static */ bool ScriptRoad::HasRoadType(TileIndex tile, RoadType road_type) { if (!ScriptMap::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(road_type)) return false; - return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE; + return ::GetAnyRoadBits(tile, ::GetRoadTramType((::RoadType)road_type), false) != ROAD_NONE; } /* static */ bool ScriptRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2) @@ -89,8 +109,9 @@ /* Tiles not neighbouring */ if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false; - RoadBits r1 = ::GetAnyRoadBits(t1, ScriptObject::GetRoadType()); - RoadBits r2 = ::GetAnyRoadBits(t2, ScriptObject::GetRoadType()); + RoadTramType rtt = ::GetRoadTramType(ScriptObject::GetRoadType()); + RoadBits r1 = ::GetAnyRoadBits(t1, rtt); // TODO + RoadBits r2 = ::GetAnyRoadBits(t2, rtt); // TODO uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3); uint dir_2 = 2 ^ dir_1; @@ -100,6 +121,16 @@ return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND); } +/* static */ bool ScriptRoad::ConvertRoadType(TileIndex start_tile, TileIndex end_tile, RoadType road_type) +{ + EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); + EnforcePrecondition(false, ::IsValidTile(start_tile)); + EnforcePrecondition(false, ::IsValidTile(end_tile)); + EnforcePrecondition(false, IsRoadTypeAvailable(road_type)); + + return ScriptObject::DoCommand(start_tile, end_tile, (::RoadType)road_type, CMD_CONVERT_ROAD); +} + /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */ /** @@ -380,7 +411,7 @@ static bool NormaliseTileOffset(int32 *tile) if (::IsNormalRoadTile(tile)) { rb = ::GetAllRoadBits(tile); } else { - for (::RoadType rt = ::ROADTYPE_BEGIN; rt < ::ROADTYPE_END; rt++) rb |= ::GetAnyRoadBits(tile, rt); + rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM); } for (uint i = 0; i < lengthof(neighbours); i++) { if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i]; @@ -392,15 +423,15 @@ static bool NormaliseTileOffset(int32 *tile) /** * Check whether one can reach (possibly by building) a road piece the center * of the neighbouring tile. This includes roads and (drive through) stations. - * @param rts The road type we want to know reachability for + * @param rt The road type we want to know reachability for * @param start_tile The tile to "enter" the neighbouring tile. * @param neighbour The direction to the neighbouring tile to "enter". * @return true if and only if the tile is reachable. */ -static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, DiagDirection neighbour) +static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagDirection neighbour) { TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour); - if ((rts & ::GetRoadTypes(neighbour_tile)) == 0) return false; + if (!HasBit(::GetPresentRoadTypes(neighbour_tile), rt)) return false; switch (::GetTileType(neighbour_tile)) { case MP_ROAD: @@ -422,13 +453,13 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - ::RoadTypes rts = ::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()); + ::RoadType rt = (::RoadType)GetCurrentRoadType(); int32 neighbour = 0; - if (TileX(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NE)) neighbour++; - if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SE)) neighbour++; - if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SW)) neighbour++; - if (TileY(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NW)) neighbour++; + if (TileX(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NE)) neighbour++; + if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SE)) neighbour++; + if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SW)) neighbour++; + if (TileY(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NW)) neighbour++; return neighbour; } @@ -460,10 +491,10 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, ::IsValidTile(end)); EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); - EnforcePrecondition(false, !one_way || ScriptObject::GetRoadType() == ::ROADTYPE_ROAD); + EnforcePrecondition(false, !one_way || RoadTypeIsRoad(ScriptObject::GetRoadType())); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); - return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 5) | 1 << 6, CMD_BUILD_LONG_ROAD); + return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 10) | 1 << 11, CMD_BUILD_LONG_ROAD); } /* static */ bool ScriptRoad::BuildRoad(TileIndex start, TileIndex end) @@ -520,11 +551,11 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); } - uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 32; + uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 4; p2 |= drive_through ? 2 : 0; p2 |= road_veh_type == ROADVEHTYPE_TRUCK ? 1 : 0; - p2 |= ::RoadTypeToRoadTypes(ScriptObject::GetRoadType()) << 2; - p2 |= entrance_dir << 6; + p2 |= ScriptObject::GetRoadType() << 5; + p2 |= entrance_dir << 3; p2 |= (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; return ScriptObject::DoCommand(tile, 1 | 1 << 8, p2, CMD_BUILD_ROAD_STOP); } @@ -588,7 +619,7 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return -1; switch (build_type) { - case BT_ROAD: return ::GetPrice(PR_BUILD_ROAD, 1, nullptr); + case BT_ROAD: return ::RoadBuildCost((::RoadType)roadtype); case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, nullptr); case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, nullptr); case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, nullptr); @@ -596,9 +627,21 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia } } +/* static */ ScriptRoad::RoadTramTypes ScriptRoad::GetRoadTramType(RoadType roadtype) +{ + return (RoadTramTypes)(1 << ::GetRoadTramType((::RoadType)roadtype)); +} + +/* static */ int32 ScriptRoad::GetMaxSpeed(RoadType road_type) +{ + if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return 0; + + return GetRoadTypeInfo((::RoadType)road_type)->max_speed; +} + /* static */ uint16 ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype) { if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0; - return roadtype == ROADTYPE_TRAM ? 3 : 2; + return GetRoadTypeInfo((::RoadType)roadtype)->maintenance_multiplier; } diff --git a/src/script/api/script_road.hpp b/src/script/api/script_road.hpp index ed4058f973..39cf0420b6 100644 --- a/src/script/api/script_road.hpp +++ b/src/script/api/script_road.hpp @@ -13,6 +13,7 @@ #define SCRIPT_ROAD_HPP #include "script_tile.hpp" +#include "../../../road.h" /** * Class that handles all road related functions. @@ -36,16 +37,21 @@ public: /** Drive through roads can't be build on town owned roads */ ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, // [STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD] - /** One way roads can't have junctions */ ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, // [STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION] + + /** This roadtype cannot have crossings */ + ERR_ROADTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED_ROAD] + + /** No suitable road could be found */ + ERR_UNSUITABLE_ROAD, // [STR_ERROR_NO_SUITABLE_ROAD, STR_ERROR_NO_SUITABLE_TRAMWAY, STR_ERROR_INCOMPATIBLE_ROAD] }; /** * Types of road known to the game. */ enum RoadType { - /* Note: these values represent part of the in-game RoadType enum */ + /* Note: these values represent part of the in-game static values */ ROADTYPE_ROAD = ::ROADTYPE_ROAD, ///< Build road objects. ROADTYPE_TRAM = ::ROADTYPE_TRAM, ///< Build tram objects. @@ -53,6 +59,14 @@ public: ROADTYPE_INVALID = -1, ///< Invalid RoadType. }; + /** + * Road/tram types + */ + enum RoadTramTypes { + ROADTRAMTYPES_ROAD = ::RTTB_ROAD, ///< Road road types. + ROADTRAMTYPES_TRAM = ::RTTB_TRAM, ///< Tram road types. + }; + /** * Type of road station. */ @@ -71,6 +85,14 @@ public: BT_TRUCK_STOP, ///< Build a truck stop }; + /** + * Get the name of a road type. + * @param road_type The road type to get the name of. + * @pre IsRoadTypeAvailable(road_type). + * @return The name the road type has. + */ + static char *GetName(RoadType road_type); + /** * Determines whether a busstop or a truckstop is needed to transport a certain cargo. * @param cargo_type The cargo to test. @@ -137,6 +159,41 @@ public: */ static void SetCurrentRoadType(RoadType road_type); + /** + * Check if a road vehicle built for a road type can run on another road type. + * @param engine_road_type The road type the road vehicle is built for. + * @param track_road_type The road type you want to check. + * @pre ScriptRoad::IsRoadTypeAvailable(engine_road_type). + * @pre ScriptRoad::IsRoadTypeAvailable(road_road_type). + * @return Whether a road vehicle built for 'engine_road_type' can run on 'road_road_type'. + */ + static bool RoadVehCanRunOnRoad(ScriptRoad::RoadType engine_road_type, ScriptRoad::RoadType road_road_type); + + /** + * Check if a road vehicle built for a road type has power on another road type. + * @param engine_road_type The road type the road vehicle is built for. + * @param road_road_type The road type you want to check. + * @pre ScriptRoad::IsRoadTypeAvailable(engine_road_type). + * @pre ScriptRoad::IsRoadTypeAvailable(road_road_type). + * @return Whether a road vehicle built for 'engine_road_type' has power on 'road_road_type'. + */ + static bool RoadVehHasPowerOnRoad(ScriptRoad::RoadType engine_road_type, ScriptRoad::RoadType road_road_type); + + + /** + * Convert the road on all tiles within a rectangle to another RoadType. + * @param start_tile One corner of the rectangle. + * @param end_tile The opposite corner of the rectangle. + * @param road_type The RoadType you want to convert. + * @pre ScriptMap::IsValidTile(start_tile). + * @pre ScriptMap::IsValidTile(end_tile). + * @pre IsRoadTypeAvailable(road_type). + * @game @pre Valid ScriptCompanyMode active in scope. + * @exception ScriptRoad::ERR_UNSUITABLE_ROAD + * @return Whether at least some road has been converted successfully. + */ + static bool ConvertRoadType(TileIndex start_tile, TileIndex end_tile, RoadType road_type); + /** * Check if a given tile has RoadType. * @param tile The tile to check. @@ -482,16 +539,35 @@ public: /** * Get the baseprice of building a road-related object. - * @param roadtype the roadtype that is build (on) + * @param roadtype the roadtype of the object to build * @param build_type the type of object to build - * @pre IsRoadTypeAvailable(railtype) + * @pre IsRoadTypeAvailable(roadtype) * @return The baseprice of building the given object. */ static Money GetBuildCost(RoadType roadtype, BuildType build_type); /** - * Get the maintenance cost factor of a roadtype. - * @param roadtype The roadtype to get the maintenance factor of. + * Test if a road type is for road or trams. + * @param roadtype the roadtype to test. + * @return RoadTramTypes of the road types. + */ + static RoadTramTypes GetRoadTramType(RoadType roadtype); + + /** + * Get the maximum speed of road vehicles running on this roadtype. + * @param road_type The roadtype to get the maximum speed of. + * @pre IsRoadTypeAvailable(road_type) + * @return The maximum speed road vehicles can run on this roadtype + * or 0 if there is no limit. + * @note The speed is in OpenTTD's internal speed unit. + * This is mph / 0.8, which is roughly 0.5 km/h. + * To get km/h multiply this number by 2.01168. + */ + static int32 GetMaxSpeed(RoadType road_type); + + /** + * Get the maintenance cost factor of a road type. + * @param roadtype The road type to get the maintenance factor of. * @pre IsRoadTypeAvailable(roadtype) * @return Maintenance cost factor of the roadtype. */ diff --git a/src/script/api/script_roadtypelist.cpp b/src/script/api/script_roadtypelist.cpp new file mode 100644 index 0000000000..a6d6c4ae60 --- /dev/null +++ b/src/script/api/script_roadtypelist.cpp @@ -0,0 +1,24 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file script_roadtypelist.cpp Implementation of ScriptRoadTypeList and friends. */ + +#include "../../stdafx.h" +#include "script_roadtypelist.hpp" +#include "../../road_func.h" + +#include "../../safeguards.h" + +ScriptRoadTypeList::ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts) +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (!HasBit(rtts, GetRoadTramType(rt))) continue; + if (ScriptObject::GetCompany() == OWNER_DEITY || ::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt); + } +} diff --git a/src/script/api/script_roadtypelist.hpp b/src/script/api/script_roadtypelist.hpp new file mode 100644 index 0000000000..cbcd7fd469 --- /dev/null +++ b/src/script/api/script_roadtypelist.hpp @@ -0,0 +1,31 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file script_roadtypelist.hpp List all available roadtypes. */ + +#ifndef SCRIPT_ROADTYPELIST_HPP +#define SCRIPT_ROADTYPELIST_HPP + +#include "script_list.hpp" +#include "script_road.hpp" + +/** + * Creates a list of all available roadtypes. + * @api ai game + * @ingroup ScriptList + */ +class ScriptRoadTypeList : public ScriptList { +public: + /** + * @param rtts Bitmask of road/tram types to list. + */ + ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts); +}; + +#endif /* SCRIPT_ROADTYPELIST_HPP */ diff --git a/src/script/api/script_station.cpp b/src/script/api/script_station.cpp index 53da51b29f..acc21076f7 100644 --- a/src/script/api/script_station.cpp +++ b/src/script/api/script_station.cpp @@ -213,13 +213,11 @@ template if (!IsValidStation(station_id)) return false; if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false; - ::RoadTypes r = RoadTypeToRoadTypes((::RoadType)road_type); - for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_BUS); rs != nullptr; rs = rs->next) { - if ((::GetRoadTypes(rs->xy) & r) != 0) return true; + if (HasBit(::GetPresentRoadTypes(rs->xy), (::RoadType)road_type)) return true; } for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_TRUCK); rs != nullptr; rs = rs->next) { - if ((::GetRoadTypes(rs->xy) & r) != 0) return true; + if (HasBit(::GetPresentRoadTypes(rs->xy), (::RoadType)road_type)) return true; } return false; diff --git a/src/script/api/script_tile.cpp b/src/script/api/script_tile.cpp index d3a4506841..7e977595b5 100644 --- a/src/script/api/script_tile.cpp +++ b/src/script/api/script_tile.cpp @@ -33,12 +33,12 @@ case MP_WATER: return IsCoast(tile); case MP_ROAD: /* Tram bits aren't considered buildable */ - if (::GetRoadTypes(tile) != ROADTYPES_ROAD) return false; + if (::GetRoadTypeTram(tile) != INVALID_ROADTYPE) return false; /* Depots and crossings aren't considered buildable */ if (::GetRoadTileType(tile) != ROAD_TILE_NORMAL) return false; - if (!HasExactlyOneBit(::GetRoadBits(tile, ROADTYPE_ROAD))) return false; - if (::IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) return true; - if (::IsRoadOwner(tile, ROADTYPE_ROAD, ScriptObject::GetCompany())) return true; + if (!HasExactlyOneBit(::GetRoadBits(tile, RTT_ROAD))) return false; + if (::IsRoadOwner(tile, RTT_ROAD, OWNER_TOWN)) return true; + if (::IsRoadOwner(tile, RTT_ROAD, ScriptObject::GetCompany())) return true; return false; } } @@ -201,7 +201,12 @@ { if (!::IsValidTile(tile)) return false; - return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, UINT32_MAX)) != TRACKDIR_BIT_NONE; + if (transport_type == TRANSPORT_ROAD) { + return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 0)) != TRACKDIR_BIT_NONE || + ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 1)) != TRACKDIR_BIT_NONE; + } else { + return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 0)) != TRACKDIR_BIT_NONE; + } } /* static */ int32 ScriptTile::GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius) diff --git a/src/script/api/script_tunnel.cpp b/src/script/api/script_tunnel.cpp index a8bfcbfd3c..ce94c17ee8 100644 --- a/src/script/api/script_tunnel.cpp +++ b/src/script/api/script_tunnel.cpp @@ -90,7 +90,7 @@ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) uint type = 0; if (vehicle_type == ScriptVehicle::VT_ROAD) { type |= (TRANSPORT_ROAD << 8); - type |= ::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()); + type |= ScriptRoad::GetCurrentRoadType(); } else { type |= (TRANSPORT_RAIL << 8); type |= ScriptRail::GetCurrentRailType(); diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index 01cfca33fd..d6711380ef 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -401,7 +401,7 @@ if (!IsValidVehicle(vehicle_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(vehicle_id) != VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; - return (ScriptRoad::RoadType)(::RoadVehicle::Get(vehicle_id))->roadtype; + return (ScriptRoad::RoadType)(int)(::RoadVehicle::Get(vehicle_id))->roadtype; } /* static */ int32 ScriptVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo) diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index def1d251f4..dcbb5d9110 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -978,9 +978,11 @@ public: WID_RV_INFO_TAB = ::WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE = ::WID_RV_STOP_REPLACE, ///< Stop Replacing button. + /* Train/road only widgets */ + WID_RV_RAIL_ROAD_TYPE_DROPDOWN = ::WID_RV_RAIL_ROAD_TYPE_DROPDOWN, ///< Dropdown menu about the rail/roadtype. + /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_DROPDOWN = ::WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, ///< Dropdown to select engines and/or wagons. - WID_RV_TRAIN_RAILTYPE_DROPDOWN = ::WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_WAGONREMOVE_TOGGLE = ::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; @@ -1194,6 +1196,8 @@ public: WID_CI_RAIL_COUNT = ::WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC = ::WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT = ::WID_CI_ROAD_COUNT, ///< Count of road. + WID_CI_TRAM_DESC = ::WID_CI_TRAM_DESC, ///< Description of tram. + WID_CI_TRAM_COUNT = ::WID_CI_TRAM_COUNT, ///< Count of tram. WID_CI_WATER_DESC = ::WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT = ::WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC = ::WID_CI_STATION_DESC, ///< Description of station. @@ -2166,6 +2170,7 @@ public: /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ + WID_ROT_CAPTION = ::WID_ROT_CAPTION, ///< Caption of the window WID_ROT_ROAD_X = ::WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y = ::WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD = ::WID_ROT_AUTOROAD, ///< Autorail. @@ -2177,6 +2182,7 @@ public: WID_ROT_BUILD_BRIDGE = ::WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL = ::WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE = ::WID_ROT_REMOVE, ///< Remove road. + WID_ROT_CONVERT_ROAD = ::WID_ROT_CONVERT_ROAD, ///< Convert road. }; /** Widgets of the #BuildRoadDepotWindow class. */ @@ -2477,6 +2483,7 @@ public: WID_TN_BUILDING_TOOLS_START = ::WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools WID_TN_RAILS = ::WID_TN_RAILS, ///< Rail building menu. WID_TN_ROADS = ::WID_TN_ROADS, ///< Road building menu. + WID_TN_TRAMS = ::WID_TN_TRAMS, ///< Tram building menu. WID_TN_WATER = ::WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR = ::WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE = ::WID_TN_LANDSCAPE, ///< Landscaping toolbar. @@ -2504,11 +2511,11 @@ public: WID_TE_TOWN_GENERATE = ::WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY = ::WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS = ::WID_TE_ROADS, ///< Road building menu. + WID_TE_TRAMS = ::WID_TE_TRAMS, ///< Tram building menu. WID_TE_WATER = ::WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES = ::WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS = ::WID_TE_SIGNS, ///< Sign building. WID_TE_DATE_PANEL = ::WID_TE_DATE_PANEL, ///< Container for the date widgets. - /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ WID_TE_MUSIC_SOUND = ::WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TE_HELP = ::WID_TE_HELP, ///< Help menu. WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. diff --git a/src/script/api/template/template_road.hpp.sq b/src/script/api/template/template_road.hpp.sq index bf9a32082a..26ef7a142e 100644 --- a/src/script/api/template/template_road.hpp.sq +++ b/src/script/api/template/template_road.hpp.sq @@ -17,6 +17,8 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadType res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptRoad::RoadTramTypes GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadTramTypes)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadTramTypes res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadVehicleType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadVehicleType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadVehicleType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::BuildType)tmp; } diff --git a/src/script/api/template/template_roadtypelist.hpp.sq b/src/script/api/template/template_roadtypelist.hpp.sq new file mode 100644 index 0000000000..5573f8614f --- /dev/null +++ b/src/script/api/template/template_roadtypelist.hpp.sq @@ -0,0 +1,21 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" + +namespace SQConvert { + /* Allow ScriptRoadTypeList to be used as Squirrel parameter */ + template <> inline ScriptRoadTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoadTypeList *)instance; } + template <> inline ScriptRoadTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoadTypeList *)instance; } + template <> inline const ScriptRoadTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoadTypeList *)instance; } + template <> inline const ScriptRoadTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoadTypeList *)instance; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRoadTypeList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "RoadTypeList", res, nullptr, DefSQDestructorCallback, true); return 1; } +} // namespace SQConvert diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index cc5e36a0e7..af30dbf9c3 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -367,28 +367,51 @@ static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) */ static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) { - if (t == MP_STATION) { - switch (GetStationType(tile)) { - case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); - case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); - case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); - case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); - case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); - default: return MKCOLOUR_FFFF; + switch (t) { + case MP_STATION: + switch (GetStationType(tile)) { + case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); + case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); + case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); + case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); + case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); + default: return MKCOLOUR_FFFF; + } + + case MP_RAILWAY: { + AndOr andor = { + MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), + _smallmap_contours_andor[t].mand + }; + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &andor); } - } else if (t == MP_RAILWAY) { - AndOr andor = { - MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), - _smallmap_contours_andor[t].mand - }; - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &andor); - } + case MP_ROAD: { + const RoadTypeInfo *rti = nullptr; + if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) { + rti = GetRoadTypeInfo(GetRoadTypeRoad(tile)); + } else { + rti = GetRoadTypeInfo(GetRoadTypeTram(tile)); + } + if (rti != nullptr) { + AndOr andor = { + MKCOLOUR_0XX0(rti->map_colour), + _smallmap_contours_andor[t].mand + }; + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &andor); + } + FALLTHROUGH; + } - /* Ground colour */ - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); + default: + /* Ground colour */ + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); + } } /** diff --git a/src/station.cpp b/src/station.cpp index 0c9b8c44d6..da55903387 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -195,7 +195,7 @@ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const for (; rs != nullptr; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ - if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; + if (!HasTileAnyRoadType(rs->xy, v->compatible_roadtypes)) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 2997c4f14e..b624957c70 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -42,6 +42,7 @@ #include "roadstop_base.h" #include "dock_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "waypoint_base.h" #include "waypoint_func.h" #include "pbs.h" @@ -988,10 +989,10 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl * @param is_truck_stop True when building a truck stop, false otherwise. * @param axis Axis of a drive-through road stop. * @param station StationID to be queried and returned if available. - * @param rts Road types to build. + * @param rt Road type to build. * @return The cost in case of success, or an error code if it failed. */ -static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes rts) +static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; @@ -1042,47 +1043,54 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags } } - RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE; - uint num_roadbits = 0; if (build_over_road) { /* There is a road, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_ROAD)) { - Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); + RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD); + if (road_rt != INVALID_ROADTYPE) { + Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD); if (road_owner == OWNER_TOWN) { if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD); } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) { CommandCost ret = CheckOwnership(road_owner); if (ret.Failed()) return ret; } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD)); + uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD)); + + if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD); + + cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces)); + } else if (RoadTypeIsRoad(rt)) { + cost.AddCost(RoadBuildCost(rt) * 2); } if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD); /* There is a tram, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_TRAM)) { - Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); + RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM); + if (tram_rt != INVALID_ROADTYPE) { + Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM); if (Company::IsValidID(tram_owner) && (!_settings_game.construction.road_stop_on_competitor_road || /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ - HasExactlyOneBit(GetRoadBits(cur_tile, ROADTYPE_TRAM)))) { + HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM)); - } + uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM)); - /* Take into account existing roadbits. */ - rts |= cur_rts; + if (RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD); + + cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces)); + } else if (RoadTypeIsTram(rt)) { + cost.AddCost(RoadBuildCost(rt) * 2); + } } else { ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); + cost.AddCost(RoadBuildCost(rt) * 2); } - - uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits; - cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build); } } @@ -1906,10 +1914,10 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * bit 6..7: Entrance direction (#DiagDirection) for normal stops. - * bit 6: #Axis of the road for drive-through stops. + * bit 2: Allow stations directly adjacent to other stations. + * bit 3..4: Entrance direction (#DiagDirection) for normal stops. + * bit 3: #Axis of the road for drive-through stops. + * bit 5..10: The roadtype. * bit 16..31: Station ID to join (NEW_STATION if build new one). * @param text Unused. * @return The cost of this operation or an error. @@ -1918,7 +1926,8 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin { bool type = HasBit(p2, 0); bool is_drive_through = HasBit(p2, 1); - RoadTypes rts = Extract(p2); + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; StationID station_to_join = GB(p2, 16, 16); bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; @@ -1938,20 +1947,18 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; - if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR; - /* Trams only have drive through stops */ - if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR; + if (!is_drive_through && RoadTypeIsTram(rt)) return CMD_ERROR; DiagDirection ddir; Axis axis; if (is_drive_through) { /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */ - axis = Extract(p2); + axis = Extract(p2); ddir = AxisToDiagDir(axis); } else { /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */ - ddir = Extract(p2); + ddir = Extract(p2); axis = DiagDirToAxis(ddir); } @@ -1961,12 +1968,12 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin /* Total road stop cost. */ CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]); StationID est = INVALID_STATION; - ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rts); + ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt); if (ret.Failed()) return ret; cost.AddCost(ret); Station *st = nullptr; - ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st); + ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 2), roadstop_area, &st); if (ret.Failed()) return ret; /* Check if this number of road stops can be allocated. */ @@ -1978,9 +1985,11 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { /* Check every tile in the area. */ TILE_AREA_LOOP(cur_tile, roadstop_area) { - RoadTypes cur_rts = GetRoadTypes(cur_tile); - Owner road_owner = HasBit(cur_rts, ROADTYPE_ROAD) ? GetRoadOwner(cur_tile, ROADTYPE_ROAD) : _current_company; - Owner tram_owner = HasBit(cur_rts, ROADTYPE_TRAM) ? GetRoadOwner(cur_tile, ROADTYPE_TRAM) : _current_company; + /* Get existing road types and owners before any tile clearing */ + RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE; + RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE; + Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company; + Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company; if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) { RemoveRoadStop(cur_tile, flags); @@ -2004,23 +2013,27 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS; if (is_drive_through) { - /* Update company infrastructure counts. If the current tile is a normal - * road tile, count only the new road bits needed to get a full diagonal road. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, cur_rts | rts) { - Company *c = Company::GetIfValid(rt == ROADTYPE_ROAD ? road_owner : tram_owner); - if (c != nullptr) { - c->infrastructure.road[rt] += 2 - (IsNormalRoadTile(cur_tile) && HasBit(cur_rts, rt) ? CountBits(GetRoadBits(cur_tile, rt)) : 0); - DirtyCompanyInfrastructureWindows(c->index); - } + /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old + * bits first. */ + if (IsNormalRoadTile(cur_tile)) { + UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD))); + UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM))); } - MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts | cur_rts, axis); + if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt; + if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt; + + UpdateCompanyRoadInfrastructure(road_rt, road_owner, 2); + UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2); + + MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis); road_stop->MakeDriveThrough(); } else { + if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt; + if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt; /* Non-drive-through stop never overbuild and always count as two road bits. */ - Company::Get(st->owner)->infrastructure.road[FIND_FIRST_BIT(rts)] += 2; - MakeRoadStop(cur_tile, st->owner, st->index, rs_type, rts, ddir); + Company::Get(st->owner)->infrastructure.road[rt] += 2; + MakeRoadStop(cur_tile, st->owner, st->index, rs_type, road_rt, tram_rt, ddir); } Company::Get(st->owner)->infrastructure.station++; @@ -2109,14 +2122,11 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) } /* Update company infrastructure counts. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -2); } + Company::Get(st->owner)->infrastructure.station--; DirtyCompanyInfrastructureWindows(st->owner); @@ -2192,16 +2202,16 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue; /* Save information on to-be-restored roads before the stop is removed. */ - RoadTypes rts = ROADTYPES_NONE; RoadBits road_bits = ROAD_NONE; + RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE }; Owner road_owner[] = { OWNER_NONE, OWNER_NONE }; - assert_compile(lengthof(road_owner) == ROADTYPE_END); if (IsDriveThroughStopTile(cur_tile)) { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(cur_tile)) { - road_owner[rt] = GetRoadOwner(cur_tile, rt); + FOR_ALL_ROADTRAMTYPES(rtt) { + road_type[rtt] = GetRoadType(cur_tile, rtt); + if (road_type[rtt] == INVALID_ROADTYPE) continue; + road_owner[rtt] = GetRoadOwner(cur_tile, rtt); /* If we don't want to preserve our roads then restore only roads of others. */ - if (keep_drive_through_roads || road_owner[rt] != _current_company) SetBit(rts, rt); + if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE; } road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile))); } @@ -2215,19 +2225,14 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui had_success = true; /* Restore roads. */ - if ((flags & DC_EXEC) && rts != ROADTYPES_NONE) { - MakeRoadNormal(cur_tile, road_bits, rts, ClosestTownFromTile(cur_tile, UINT_MAX)->index, - road_owner[ROADTYPE_ROAD], road_owner[ROADTYPE_TRAM]); + if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) { + MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index, + road_owner[RTT_ROAD], road_owner[RTT_TRAM]); /* Update company infrastructure counts. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, rts) { - Company *c = Company::GetIfValid(GetRoadOwner(cur_tile, rt)); - if (c != nullptr) { - c->infrastructure.road[rt] += CountBits(road_bits); - DirtyCompanyInfrastructureWindows(c->index); - } - } + int count = CountBits(road_bits); + UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count); + UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_ROAD], count); } } @@ -2939,7 +2944,6 @@ static void DrawTile_Station(TileInfo *ti) const NewGRFSpriteLayout *layout = nullptr; DrawTileSprites tmp_rail_layout; const DrawTileSprites *t = nullptr; - RoadTypes roadtypes; int32 total_offset; const RailtypeInfo *rti = nullptr; uint32 relocation = 0; @@ -2950,7 +2954,6 @@ static void DrawTile_Station(TileInfo *ti) if (HasStationRail(ti->tile)) { rti = GetRailTypeInfo(GetRailType(ti->tile)); - roadtypes = ROADTYPES_NONE; total_offset = rti->GetRailtypeSpriteOffset(); if (IsCustomStationSpecIndex(ti->tile)) { @@ -2977,7 +2980,6 @@ static void DrawTile_Station(TileInfo *ti) } } } else { - roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE; total_offset = 0; } @@ -3162,10 +3164,30 @@ draw_default_foundation: if (HasStationRail(ti->tile) && HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(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); - DrawRoadCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y); + if (IsRoadStop(ti->tile)) { + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo* tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + if (IsDriveThroughStopTile(ti->tile)) { + Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; + uint sprite_offset = axis == AXIS_X ? 1 : 0; + + DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset); + } else { + /* Non-drivethrough road stops are only valid for roads. */ + assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE); + + if (road_rti->UsesOverlay()) { + DiagDirection dir = GetRoadStopDir(ti->tile); + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP); + DrawGroundSprite(ground + dir, PAL_NONE); + } + } + + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); } if (IsRailWaypoint(ti->tile)) { @@ -3199,8 +3221,29 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? 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); + if (roadtype != INVALID_ROADTYPE) { + const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype); + if (image >= 4) { + /* Drive-through stop */ + uint sprite_offset = 5 - image; + + /* Road underlay takes precendence over tram */ + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND); + DrawSprite(ground + sprite_offset, PAL_NONE, x, y); + + SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY); + if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y); + } else if (RoadTypeIsTram(roadtype)) { + DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y); + } + } else { + /* Drive-in stop */ + if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP); + DrawSprite(ground + image, PAL_NONE, x, y); + } + } } /* Default waypoint has no railtype specific sprites */ @@ -3220,28 +3263,44 @@ static Foundation GetFoundation_Station(TileIndex tile, Slope tileh) static void GetTileDesc_Station(TileIndex tile, TileDesc *td) { td->owner[0] = GetTileOwner(tile); - if (IsDriveThroughStopTile(tile)) { + + if (IsRoadStopTile(tile)) { + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); - - /* Is there a mix of owners? */ - if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || - (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { - uint i = 1; - if (road_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; - td->owner[i] = road_owner; - i++; - } - if (tram_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; - td->owner[i] = tram_owner; + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } + + if (IsDriveThroughStopTile(tile)) { + /* Is there a mix of owners? */ + if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || + (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { + uint i = 1; + if (road_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; + td->owner[i] = road_owner; + i++; + } + if (tram_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; + td->owner[i] = tram_owner; + } } } } + td->build_date = BaseStation::GetByTile(tile)->build_date; if (HasStationTileRail(tile)) { @@ -3327,7 +3386,10 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode break; case TRANSPORT_ROAD: - if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) { + if (IsRoadStop(tile)) { + RoadTramType rtt = (RoadTramType)sub_mode; + if (!HasTileRoadType(tile, rtt)) break; + DiagDirection dir = GetRoadStopDir(tile); Axis axis = DiagDirToAxis(dir); @@ -4249,15 +4311,16 @@ void DeleteOilRig(TileIndex tile) static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner) { if (IsRoadStopTile(tile)) { - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - if (HasTileRoadType(tile, rt)) { + if (GetRoadOwner(tile, rtt) == old_owner) { + RoadType rt = GetRoadType(tile, rtt); + if (rt != INVALID_ROADTYPE) { /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.road[rt] -= 2; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2; } - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } } @@ -4338,17 +4401,16 @@ static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags) /* Yeah... water can always remove stops, right? */ if (_current_company == OWNER_WATER) return true; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_TRAM)) { - Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + if (GetRoadTypeTram(tile) != INVALID_ROADTYPE) { + Owner tram_owner = GetRoadOwner(tile, RTT_TRAM); if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false; } - if (HasBit(rts, ROADTYPE_ROAD)) { - Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); + if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) { + Owner road_owner = GetRoadOwner(tile, RTT_ROAD); if (road_owner != OWNER_TOWN) { if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false; } else { - if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags).Failed()) return false; + if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, RTT_ROAD), OWNER_TOWN, RTT_ROAD, flags).Failed()) return false; } } @@ -4369,8 +4431,8 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags) case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST); - case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); - case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); + case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); + case STATION_BUS: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST); case STATION_OILRIG: diff --git a/src/station_func.h b/src/station_func.h index 1ca3fd7aef..6823bdad5b 100644 --- a/src/station_func.h +++ b/src/station_func.h @@ -18,6 +18,7 @@ #include "vehicle_type.h" #include "economy_func.h" #include "rail.h" +#include "road.h" #include "linkgraph/linkgraph_type.h" #include "industry_type.h" diff --git a/src/station_map.h b/src/station_map.h index 0d21a306d0..7947d4228a 100644 --- a/src/station_map.h +++ b/src/station_map.h @@ -17,6 +17,7 @@ #include "water_map.h" #include "station_func.h" #include "rail.h" +#include "road.h" typedef byte StationGfx; ///< Index of station graphics. @see _station_display_datas @@ -583,15 +584,16 @@ static inline void MakeRailWaypoint(TileIndex t, Owner o, StationID sid, Axis a, * @param o the owner of the roadstop * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile - * @param rt the roadtypes on this tile + * @param road_rt the road roadtype on this tile + * @param tram_rt the tram roadtype on this tile * @param d the direction of the roadstop */ -static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadTypes rt, DiagDirection d) +static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, DiagDirection d) { MakeStation(t, o, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), d); - SetRoadTypes(t, rt); - SetRoadOwner(t, ROADTYPE_ROAD, o); - SetRoadOwner(t, ROADTYPE_TRAM, o); + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_ROAD, o); + SetRoadOwner(t, RTT_TRAM, o); } /** @@ -602,15 +604,16 @@ static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopTyp * @param tram the owner of the tram * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile - * @param rt the roadtypes on this tile + * @param road_rt the road roadtype on this tile + * @param tram_rt the tram roadtype on this tile * @param a the direction of the roadstop */ -static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadTypes rt, Axis a) +static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, Axis a) { MakeStation(t, station, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + a); - SetRoadTypes(t, rt); - SetRoadOwner(t, ROADTYPE_ROAD, road); - SetRoadOwner(t, ROADTYPE_TRAM, tram); + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_ROAD, road); + SetRoadOwner(t, RTT_TRAM, tram); } /** diff --git a/src/table/engines.h b/src/table/engines.h index a5acd28439..7a40e4f7ed 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -669,7 +669,7 @@ static const AircraftVehicleInfo _orig_aircraft_vehicle_info[] = { * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ -#define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0 } +#define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0, ROADTYPE_ROAD } static const RoadVehicleInfo _orig_road_vehicle_info[] = { /* image_index sfx max_speed power * | cost_factor | | capacity | diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 7a75acd701..69d0e6187d 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -11,6 +11,7 @@ #include "../newgrf_house.h" #include "../newgrf_engine.h" +#include "../newgrf_roadtype.h" /* Helper for filling property tables */ #define NIP(prop, base, variable, type, name) { name, (ptrdiff_t)cpp_offsetof(base, variable), cpp_sizeof(base, variable), prop, type } @@ -58,7 +59,7 @@ static const NIVariable _niv_vehicles[] = { NIV(0x47, "vehicle cargo info"), NIV(0x48, "vehicle type info"), NIV(0x49, "year of construction"), - NIV(0x4A, "current rail type info"), + NIV(0x4A, "current rail/road type info"), NIV(0x4B, "long date of last service"), NIV(0x4C, "current max speed"), NIV(0x4D, "position in articulated vehicle"), @@ -676,6 +677,48 @@ static const NIFeature _nif_station_struct = { new NIHStationStruct(), }; +/*** NewGRF road types ***/ + +static const NIVariable _niv_roadtypes[] = { + NIV(0x40, "terrain type"), + NIV(0x41, "enhanced tunnels"), + NIV(0x42, "level crossing status"), + NIV(0x43, "construction date"), + NIV(0x44, "town zone"), + NIV_END() +}; + +class NIHRoadType : public NIHelper { + bool IsInspectable(uint index) const override { return true; } + uint GetParent(uint index) const override { return UINT32_MAX; } + const void *GetInstance(uint index) const override { return nullptr; } + const void *GetSpec(uint index) const override { return nullptr; } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } + uint32 GetGRFID(uint index) const override { return 0; } + + uint Resolve(uint index, uint var, uint param, bool *avail) const override + { + /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. + * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ + RoadTypeResolverObject ro(nullptr, index, TCX_NORMAL, ROTSG_END); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + } +}; + +static const NIFeature _nif_roadtype = { + nullptr, + nullptr, + _niv_roadtypes, + new NIHRoadType(), +}; + +static const NIFeature _nif_tramtype = { + nullptr, + nullptr, + _niv_roadtypes, + new NIHRoadType(), +}; + /** Table with all NIFeatures. */ static const NIFeature * const _nifeatures[] = { &_nif_vehicle, // GSF_TRAINS @@ -696,6 +739,8 @@ static const NIFeature * const _nifeatures[] = { &_nif_object, // GSF_OBJECTS &_nif_railtype, // GSF_RAILTYPES &_nif_airporttile, // GSF_AIRPORTTILES + &_nif_roadtype, // GSF_ROADTYPES + &_nif_tramtype, // GSF_TRAMTYPES &_nif_town, // GSF_FAKE_TOWNS &_nif_station_struct, // GSF_FAKE_STATION_STRUCT }; diff --git a/src/table/railtypes.h b/src/table/railtypes.h index 73b73ff802..829b223b5e 100644 --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -156,7 +156,7 @@ static const RailtypeInfo _original_railtypes[] = { STR_RAIL_MENU_ELRAIL_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION, STR_REPLACE_ELRAIL_VEHICLES, - STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE, + STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE, }, /* Offset of snow tiles */ diff --git a/src/table/road_land.h b/src/table/road_land.h index 19b8f57119..2b3a4177f8 100644 --- a/src/table/road_land.h +++ b/src/table/road_land.h @@ -41,35 +41,6 @@ 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_COLOUR), PAL_NONE, 0, 15, 16, 1) - TILE_SEQ_END() -}; - -static const DrawTileSeqStruct _tram_depot_SE[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x31) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 1, 16) - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x32) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) - TILE_SEQ_END() -}; - -static const DrawTileSeqStruct _tram_depot_SW[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x33) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 1) - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x34) | (1 << PALETTE_MODIFIER_COLOUR), 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_COLOUR), 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 } -}; - /* Sprite layout for level crossings. The SpriteIDs are actually offsets * from the base SpriteID returned from the NewGRF sprite resolver. */ static const DrawTileSeqStruct _crossing_layout_ALL[] = { diff --git a/src/table/roadtypes.h b/src/table/roadtypes.h new file mode 100644 index 0000000000..348cdb677b --- /dev/null +++ b/src/table/roadtypes.h @@ -0,0 +1,183 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file roadtypes.h + * All the roadtype-specific information is stored here. + */ + +#ifndef ROADTYPES_H +#define ROADTYPES_H + +/** + * Global Roadtype definition + */ +static const RoadTypeInfo _original_roadtypes[] = { + /* Road */ + { + /* GUI sprites */ + { + SPR_IMG_ROAD_X_DIR, + SPR_IMG_ROAD_Y_DIR, + SPR_IMG_AUTOROAD, + SPR_IMG_ROAD_DEPOT, + SPR_IMG_ROAD_TUNNEL, + SPR_IMG_CONVERT_ROAD, + }, + + { + SPR_CURSOR_ROAD_NESW, + SPR_CURSOR_ROAD_NWSE, + SPR_CURSOR_AUTOROAD, + SPR_CURSOR_ROAD_DEPOT, + SPR_CURSOR_TUNNEL_RAIL, + SPR_CURSOR_CONVERT_ROAD, + }, + + /* strings */ + { + STR_ROAD_NAME_ROAD, + STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, + STR_ROAD_MENU_ROAD_CONSTRUCTION, + STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION, + STR_REPLACE_ROAD_VEHICLES, + STR_ENGINE_PREVIEW_ROAD_VEHICLE, + + STR_ERROR_CAN_T_BUILD_ROAD_HERE, + STR_ERROR_CAN_T_REMOVE_ROAD_FROM, + STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, + { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, + { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, + STR_ERROR_CAN_T_CONVERT_ROAD, + { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, + { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, + }, + + /* Powered roadtypes */ + ROADTYPES_ROAD, + + /* flags */ + ROTFB_TOWN_BUILD, + + /* cost multiplier */ + 8, + + /* maintenance cost multiplier */ + 16, + + /* max speed */ + 0, + + /* road type label */ + 'ROAD', + + /* alternate labels */ + RoadTypeLabelList(), + + /* map colour */ + 0x01, + + /* introduction date */ + MIN_YEAR, + + /* roadtypes required for this to be introduced */ + ROADTYPES_NONE, + + /* introduction road types */ + ROADTYPES_ROAD, + + /* sort order */ + 0x07, + + { nullptr }, + { nullptr }, + }, + + /* Electrified Tram */ + { + /* GUI sprites */ + { + SPR_IMG_TRAMWAY_X_DIR, + SPR_IMG_TRAMWAY_Y_DIR, + SPR_IMG_AUTOTRAM, + SPR_IMG_ROAD_DEPOT, + SPR_IMG_ROAD_TUNNEL, + SPR_IMG_CONVERT_TRAM, + }, + + { + SPR_CURSOR_TRAMWAY_NESW, + SPR_CURSOR_TRAMWAY_NWSE, + SPR_CURSOR_AUTOTRAM, + SPR_CURSOR_ROAD_DEPOT, + SPR_CURSOR_TUNNEL_RAIL, + SPR_CURSOR_CONVERT_TRAM, + }, + + /* strings */ + { + STR_ROAD_NAME_TRAM, + STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, + STR_ROAD_MENU_TRAM_CONSTRUCTION, + STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION, + STR_REPLACE_TRAM_VEHICLES, + STR_ENGINE_PREVIEW_TRAM_VEHICLE, + + STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, + STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, + STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, + { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, + { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, + STR_ERROR_CAN_T_CONVERT_TRAMWAY, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, + }, + + /* Powered roadtypes */ + ROADTYPES_TRAM, + + /* flags */ + ROTFB_CATENARY | ROTFB_NO_HOUSES, + + /* cost multiplier */ + 16, + + /* maintenance cost multiplier */ + 24, + + /* max speed */ + 0, + + /* road type label */ + 'ELRL', + + /* alternate labels */ + RoadTypeLabelList(), + + /* map colour */ + 0x01, + + /* introduction date */ + INVALID_DATE, + + /* roadtypes required for this to be introduced */ + ROADTYPES_NONE, + + /* introduction road types */ + ROADTYPES_TRAM, + + /* sort order */ + 0x17, + + { nullptr }, + { nullptr }, + }, +}; + +#endif /* ROADTYPES_H */ diff --git a/src/table/sprites.h b/src/table/sprites.h index 1f4f8caf84..5cc16b918e 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -56,7 +56,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682; /** Extra graphic spritenumbers */ static const SpriteID SPR_OPENTTD_BASE = 4896; -static const uint16 OPENTTD_SPRITE_COUNT = 179; +static const uint16 OPENTTD_SPRITE_COUNT = 184; /* Halftile-selection sprites */ static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE; @@ -281,13 +281,15 @@ static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_W = SPR_TRAMWAY_BASE + 24; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_E = SPR_TRAMWAY_BASE + 26; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_Y = SPR_TRAMWAY_BASE + 46; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_X = SPR_TRAMWAY_BASE + 47; +static const SpriteID SPR_TRAMWAY_DEPOT_WITH_TRACK = SPR_TRAMWAY_BASE + 49; static const SpriteID SPR_TRAMWAY_BACK_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 55; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 56; static const SpriteID SPR_TRAMWAY_BACK_WIRES_SLOPED = SPR_TRAMWAY_BASE + 72; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_SLOPED = SPR_TRAMWAY_BASE + 68; static const SpriteID SPR_TRAMWAY_TUNNEL_WIRES = SPR_TRAMWAY_BASE + 80; static const SpriteID SPR_TRAMWAY_BRIDGE = SPR_TRAMWAY_BASE + 107; -static const uint16 TRAMWAY_SPRITE_COUNT = 113; +static const SpriteID SPR_TRAMWAY_DEPOT_NO_TRACK = SPR_TRAMWAY_BASE + 113; +static const uint16 TRAMWAY_SPRITE_COUNT = 119; /** One way road sprites */ static const SpriteID SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + TRAMWAY_SPRITE_COUNT; @@ -596,6 +598,7 @@ static const SpriteID SPR_ROAD_SLOPE_START = 1343; static const SpriteID SPR_ROAD_Y_SNOW = 1351; static const SpriteID SPR_ROAD_X_SNOW = 1352; /* see _road_sloped_sprites_offset in road_cmd.cpp for offsets for sloped road tiles */ +static const SpriteID SPR_ROAD_DEPOT = 1408; static const SpriteID SPR_EXCAVATION_X = 1414; static const SpriteID SPR_EXCAVATION_Y = 1415; @@ -1132,6 +1135,7 @@ static const SpriteID SPR_IMG_ZOOMIN = 735; static const SpriteID SPR_IMG_ZOOMOUT = 736; static const SpriteID SPR_IMG_BUILDRAIL = 727; static const SpriteID SPR_IMG_BUILDROAD = 728; +static const SpriteID SPR_IMG_BUILDTRAMS = SPR_OPENTTD_BASE + 179; static const SpriteID SPR_IMG_BUILDWATER = 729; static const SpriteID SPR_IMG_BUILDAIR = 730; static const SpriteID SPR_IMG_LANDSCAPING = 4083; @@ -1378,6 +1382,11 @@ static const SpriteID SPR_IMG_GOAL = SPR_OPENTTD_BASE + 171; static const SpriteID SPR_IMG_GOAL_COMPLETED = SPR_OPENTTD_BASE + 172; static const SpriteID SPR_IMG_GOAL_BROKEN_REF= SPR_OPENTTD_BASE + 173; +static const SpriteID SPR_IMG_CONVERT_ROAD = SPR_OPENTTD_BASE + 180; +static const CursorID SPR_CURSOR_CONVERT_ROAD = SPR_OPENTTD_BASE + 181; +static const SpriteID SPR_IMG_CONVERT_TRAM = SPR_OPENTTD_BASE + 182; +static const CursorID SPR_CURSOR_CONVERT_TRAM = SPR_OPENTTD_BASE + 183; + /* intro_gui.cpp, genworld_gui.cpp */ static const SpriteID SPR_SELECT_TEMPERATE = 4882; static const SpriteID SPR_SELECT_TEMPERATE_PUSHED = 4883; diff --git a/src/tile_cmd.h b/src/tile_cmd.h index 84a3eebc28..4a9be67d5f 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -66,7 +66,10 @@ struct TileDesc { StringID railtype2; ///< Type of second rail on the tile. uint16 rail_speed; ///< Speed limit of rail (bridges and track) uint16 rail_speed2; ///< Speed limit of second rail (bridges and track) - uint16 road_speed; ///< Speed limit of road (bridges) + StringID roadtype; ///< Type of road on the tile. + uint16 road_speed; ///< Speed limit of road (bridges and track) + StringID tramtype; ///< Type of tram on the tile. + uint16 tram_speed; ///< Speed limit of tram (bridges and track) }; /** diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 457962388e..aded838763 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -17,6 +17,7 @@ #include "command_func.h" #include "vehicle_gui.h" #include "rail_gui.h" +#include "road.h" #include "road_gui.h" #include "date_func.h" #include "vehicle_func.h" @@ -66,6 +67,7 @@ uint _toolbar_width = 0; RailType _last_built_railtype; RoadType _last_built_roadtype; +RoadType _last_built_tramtype; static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. @@ -906,22 +908,7 @@ static CallBackFunction MenuClickBuildRail(int index) static CallBackFunction ToolbarBuildRoadClick(Window *w) { - const Company *c = Company::Get(_local_company); - DropDownList list; - - /* Road is always visible and available. */ - list.emplace_back(new DropDownListIconItem(SPR_IMG_ROAD_X_DIR, PAL_NONE, STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false)); - - /* Tram is only visible when there will be a tram, and available when that has been introduced. */ - Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { - if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue; - - list.emplace_back(new DropDownListIconItem(SPR_IMG_TRAMWAY_X_DIR, PAL_NONE, STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM))); - break; - } - ShowDropDownList(w, std::move(list), _last_built_roadtype, WID_TN_ROADS, 140, true, true); + ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -939,6 +926,28 @@ static CallBackFunction MenuClickBuildRoad(int index) return CBF_NONE; } +/* --- Tram button menu --- */ + +static CallBackFunction ToolbarBuildTramClick(Window *w) +{ + ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Tram menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildTram(int index) +{ + _last_built_tramtype = (RoadType)index; + ShowBuildRoadToolbar(_last_built_tramtype); + return CBF_NONE; +} + /* --- Water button menu --- */ static CallBackFunction ToolbarBuildWaterClick(Window *w) @@ -1264,9 +1273,41 @@ static CallBackFunction ToolbarScenGenIndustry(Window *w) static CallBackFunction ToolbarScenBuildRoadClick(Window *w) { - w->HandleButtonClick(WID_TE_ROADS); + ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildRoadScenToolbar(); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Road menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarScenBuildRoad(int index) +{ + _last_built_roadtype = (RoadType)index; + ShowBuildRoadScenToolbar(_last_built_roadtype); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenBuildTramClick(Window *w) +{ + ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Tram menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarScenBuildTram(int index) +{ + _last_built_tramtype = (RoadType)index; + ShowBuildRoadScenToolbar(_last_built_tramtype); return CBF_NONE; } @@ -1324,12 +1365,13 @@ static MenuClickedProc * const _menu_clicked_procs[] = { nullptr, // 20 MenuClickBuildRail, // 21 MenuClickBuildRoad, // 22 - MenuClickBuildWater, // 23 - MenuClickBuildAir, // 24 - MenuClickForest, // 25 - MenuClickMusicWindow, // 26 - MenuClickNewspaper, // 27 - MenuClickHelp, // 28 + MenuClickBuildTram, // 23 + MenuClickBuildWater, // 24 + MenuClickBuildAir, // 25 + MenuClickForest, // 26 + MenuClickMusicWindow, // 27 + MenuClickNewspaper, // 28 + MenuClickHelp, // 29 }; /** Full blown container to make it behave exactly as we want :) */ @@ -1785,6 +1827,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { WID_TN_ZOOM_OUT, WID_TN_RAILS, WID_TN_ROADS, + WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, @@ -1845,6 +1888,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1864,6 +1908,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1877,6 +1922,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1952,6 +1998,7 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = { ToolbarZoomOutClick, ToolbarBuildRailClick, ToolbarBuildRoadClick, + ToolbarBuildTramClick, ToolbarBuildWaterClick, ToolbarBuildAirClick, ToolbarForestClick, @@ -1986,6 +2033,7 @@ enum MainToolbarHotkeys { MTHK_ZOOM_OUT, MTHK_BUILD_RAIL, MTHK_BUILD_ROAD, + MTHK_BUILD_TRAM, MTHK_BUILD_DOCKS, MTHK_BUILD_AIRPORT, MTHK_BUILD_TREES, @@ -2031,7 +2079,7 @@ struct MainToolbarWindow : Window { /* If spectator, disable all construction buttons * ie : Build road, rail, ships, airports and landscaping * Since enabled state is the default, just disable when needed */ - this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); + this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); /* disable company list drop downs, if there are no companies */ this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFT, WIDGET_LIST_END); @@ -2039,6 +2087,8 @@ struct MainToolbarWindow : Window { this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN)); + this->SetWidgetDisabledState(WID_TN_ROADS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_ROAD)); + this->SetWidgetDisabledState(WID_TN_TRAMS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)); this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); this->DrawWidgets(); @@ -2082,6 +2132,7 @@ struct MainToolbarWindow : Window { case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break; case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break; + case MTHK_BUILD_TRAM: if (CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)) ShowBuildRoadToolbar(_last_built_tramtype); break; case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break; case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break; @@ -2194,6 +2245,7 @@ static Hotkey maintoolbar_hotkeys[] = { Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT), Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL), Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD), + Hotkey((uint16)0, "build_tram", MTHK_BUILD_TRAM), Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS), Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT), Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES), @@ -2240,6 +2292,7 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT SPR_IMG_BUILDRAIL, // WID_TN_RAILS SPR_IMG_BUILDROAD, // WID_TN_ROADS + SPR_IMG_BUILDTRAMS, // WID_TN_TRAMS SPR_IMG_BUILDWATER, // WID_TN_WATER SPR_IMG_BUILDAIR, // WID_TN_AIR SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE @@ -2298,14 +2351,15 @@ static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = { nullptr, // 11 nullptr, // 12 nullptr, // 13 - nullptr, // 14 - nullptr, // 15 + ToolbarScenBuildRoad, // 14 + ToolbarScenBuildTram, // 15 nullptr, // 16 nullptr, // 17 nullptr, // 18 - MenuClickMusicWindow, // 19 - MenuClickHelp, // 20 - nullptr, // 21 + nullptr, // 19 + MenuClickMusicWindow, // 20 + MenuClickHelp, // 21 + nullptr, // 22 }; static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { @@ -2324,6 +2378,7 @@ static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { ToolbarScenGenTown, ToolbarScenGenIndustry, ToolbarScenBuildRoadClick, + ToolbarScenBuildTramClick, ToolbarScenBuildDocks, ToolbarScenPlantTrees, ToolbarScenPlaceSign, @@ -2342,6 +2397,7 @@ enum MainToolbarEditorHotkeys { MTEHK_GENTOWN, MTEHK_GENINDUSTRY, MTEHK_BUILD_ROAD, + MTEHK_BUILD_TRAM, MTEHK_BUILD_DOCKS, MTEHK_BUILD_TREES, MTEHK_SIGN, @@ -2382,6 +2438,8 @@ struct ScenarioEditorToolbarWindow : Window { { this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR); + this->SetWidgetDisabledState(WID_TE_ROADS, (GetRoadTypes(true) & ~_roadtypes_type) == ROADTYPES_NONE); + this->SetWidgetDisabledState(WID_TE_TRAMS, (GetRoadTypes(true) & _roadtypes_type) == ROADTYPES_NONE); this->DrawWidgets(); } @@ -2448,6 +2506,7 @@ struct ScenarioEditorToolbarWindow : Window { case MTEHK_GENTOWN: ToolbarScenGenTown(this); break; case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break; case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break; + case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break; case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break; case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break; case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break; @@ -2551,6 +2610,7 @@ static Hotkey scenedit_maintoolbar_hotkeys[] = { Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN), Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY), Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD), + Hotkey((uint16)0, "build_tram", MTEHK_BUILD_TRAM), Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS), Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES), Hotkey(WKC_F10, "build_sign", MTEHK_SIGN), @@ -2593,7 +2653,8 @@ static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TRAMS), SetDataTip(SPR_IMG_BUILDTRAMS, STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), @@ -2625,6 +2686,7 @@ void AllocateToolbar() { /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ _last_built_roadtype = ROADTYPE_ROAD; + _last_built_tramtype = ROADTYPE_TRAM; if (_game_mode == GM_EDITOR) { new ScenarioEditorToolbarWindow(&_toolb_scen_desc); diff --git a/src/town.h b/src/town.h index 3ff4651c97..0ce9ebaa9c 100644 --- a/src/town.h +++ b/src/town.h @@ -342,4 +342,6 @@ static inline uint16 TownTicksToGameTicks(uint16 ticks) { extern CargoTypes _town_cargoes_accepted; +RoadType GetTownRoadType(const Town *t); + #endif /* TOWN_H */ diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 99bb0aacfc..a7396b2a5e 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -13,6 +13,7 @@ #include +#include "road.h" #include "road_internal.h" /* Cleaning up road bits */ #include "road_cmd.h" #include "landscape.h" @@ -1071,7 +1072,38 @@ static RoadBits GetTownRoadBits(TileIndex tile) { if (IsRoadDepotTile(tile) || IsStandardRoadStopTile(tile)) return ROAD_NONE; - return GetAnyRoadBits(tile, ROADTYPE_ROAD, true); + return GetAnyRoadBits(tile, RTT_ROAD, true); +} + +RoadType GetTownRoadType(const Town *t) +{ + RoadType best_rt = ROADTYPE_ROAD; + const RoadTypeInfo *best = nullptr; + const uint16 assume_max_speed = 50; + + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsTram(rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + /* Unused road type. */ + if (rti->label == 0) continue; + + /* Can town build this road. */ + if (!HasBit(rti->flags, ROTF_TOWN_BUILD)) continue; + + /* Not yet introduced at this date. */ + if (IsInsideMM(rti->introduction_date, 0, MAX_DAY) && rti->introduction_date > _date) continue; + + if (best != nullptr) { + if ((rti->max_speed == 0 ? assume_max_speed : rti->max_speed) < (best->max_speed == 0 ? assume_max_speed : best->max_speed)) continue; + } + + best_rt = rt; + best = rti; + } + + return best_rt; } /** @@ -1130,7 +1162,8 @@ static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir) /* No, try if we are able to build a road piece there. * If that fails clear the land, and if that fails exit. * This is to make sure that we can build a road here later. */ - if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() && + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X) | (rt << 4), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() && DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR).Failed()) { return false; } @@ -1298,7 +1331,8 @@ static bool GrowTownWithExtraHouse(Town *t, TileIndex tile) */ static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd) { - if (DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) { + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, rcmd | (rt << 4), t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) { _grow_town_result = GROWTH_SUCCEED; return true; } @@ -1363,8 +1397,9 @@ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDi for (;;) { /* Can we actually build the bridge? */ - if (DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) { - DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE); + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, bridge_tile, bridge_type | rt << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) { + DoCommand(tile, bridge_tile, bridge_type | rt << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE); _grow_town_result = GROWTH_SUCCEED; return true; } @@ -1387,6 +1422,37 @@ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDi return false; } + +/** + * Checks whether at least one surrounding roads allows to build a house here + * + * @param t the tile where the house will be built + * @return true if at least one surrounding roadtype allows building houses here + */ +static inline bool RoadTypesAllowHouseHere(TileIndex t) +{ + static const TileIndexDiffC tiles[] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; + bool allow = false; + + for (const TileIndexDiffC *ptr = tiles; ptr != endof(tiles); ++ptr) { + TileIndex cur_tile = t + ToTileIndexDiff(*ptr); + if (!IsValidTile(cur_tile)) continue; + + if (!(IsTileType(cur_tile, MP_ROAD) || IsTileType(cur_tile, MP_STATION))) continue; + allow = true; + + RoadType road_rt = GetRoadTypeRoad(cur_tile); + RoadType tram_rt = GetRoadTypeTram(cur_tile); + if (road_rt != INVALID_ROADTYPE && !HasBit(GetRoadTypeInfo(road_rt)->flags, ROTF_NO_HOUSES)) return true; + if (tram_rt != INVALID_ROADTYPE && !HasBit(GetRoadTypeInfo(tram_rt)->flags, ROTF_NO_HOUSES)) return true; + } + + /* If no road was found surrounding the tile we can allow building the house since there is + * nothing which forbids it, if a road was found but the execution reached this point, then + * all the found roads don't allow houses to be built */ + return !allow; +} + /** * Grows the given town. * There are at the moment 3 possible way's for @@ -1565,6 +1631,8 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t } } + allow_house &= RoadTypesAllowHouseHere(house_tile); + if (allow_house) { /* Build a house, but not if there already is a house there. */ if (!IsTileType(house_tile, MP_HOUSE)) { @@ -1704,14 +1772,14 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) } tile = TileAddByDiagDir(tile, target_dir); - if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) { + if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, RTT_ROAD)) { /* Don't allow building over roads of other cities */ - if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { + if (IsRoadOwner(tile, RTT_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { return false; - } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { + } else if (IsRoadOwner(tile, RTT_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { /* If we are in the SE, and this road-piece has no town owner yet, it just found an * owner :) (happy happy happy road now) */ - SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN); + SetRoadOwner(tile, RTT_ROAD, OWNER_TOWN); SetTownIndex(tile, t->index); } } @@ -1785,7 +1853,8 @@ static bool GrowTown(Town *t) /* Only work with plain land that not already has a house */ if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) { if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) { - DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); + RoadType rt = GetTownRoadType(t); + DoCommand(tile, GenRandomRoadBits() | (rt << 4), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); cur_company.Restore(); return true; } @@ -2414,6 +2483,9 @@ static inline CommandCost CanBuildHouseHere(TileIndex tile, TownID town, bool no if (IsSteepSlope(GetTileSlope(tile))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } + /* at least one RoadTypes allow building the house here? */ + if (!RoadTypesAllowHouseHere(tile)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD); + /* building under a bridge? */ if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); diff --git a/src/tunnel_map.h b/src/tunnel_map.h index e1f3f28966..c6c2125943 100644 --- a/src/tunnel_map.h +++ b/src/tunnel_map.h @@ -121,7 +121,7 @@ static inline void SetTunnelIndex(TileIndex t, TunnelID id) * @param d the direction facing out of the tunnel * @param r the road type used in the tunnel */ -static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RoadTypes r) +static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RoadType road_rt, RoadType tram_rt) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); @@ -132,9 +132,9 @@ static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirecti SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; _me[t].m8 = 0; - SetRoadOwner(t, ROADTYPE_ROAD, o); - if (o != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, o); - SetRoadTypes(t, r); + SetRoadOwner(t, RTT_ROAD, o); + if (o != OWNER_TOWN) SetRoadOwner(t, RTT_TRAM, o); + SetRoadTypes(t, road_rt, tram_rt); } /** diff --git a/src/tunnelbridge.h b/src/tunnelbridge.h index f200974ee9..039a2da0ca 100644 --- a/src/tunnelbridge.h +++ b/src/tunnelbridge.h @@ -13,6 +13,7 @@ #define TUNNELBRIDGE_H #include "map_func.h" +#include "tile_map.h" void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END); void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END); @@ -36,6 +37,18 @@ static inline uint GetTunnelBridgeLength(TileIndex begin, TileIndex end) return abs(x2 + y2 - x1 - y1) - 1; } +/** + * Sets the ownership of the bridge/tunnel ramps + * @param begin The begin of the tunnel or bridge. + * @param end The end of the tunnel or bridge. + * @param owner The new owner to set + */ +static inline void SetTunnelBridgeOwner(TileIndex begin, TileIndex end, Owner owner) +{ + SetTileOwner(begin, owner); + SetTileOwner(end, owner); +} + extern TileIndex _build_tunnel_endtile; #endif /* TUNNELBRIDGE_H */ diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index a36a54ad27..9d6a1a9cfb 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -40,6 +40,7 @@ #include "pbs.h" #include "company_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "object_base.h" #include "water.h" #include "company_gui.h" @@ -287,7 +288,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u CompanyID company = _current_company; RailType railtype = INVALID_RAILTYPE; - RoadTypes roadtypes = ROADTYPES_NONE; + RoadType roadtype = INVALID_ROADTYPE; /* unpack parameters */ BridgeType bridge_type = GB(p2, 0, 8); @@ -299,8 +300,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u /* type of bridge */ switch (transport_type) { case TRANSPORT_ROAD: - roadtypes = Extract(p2); - if (!HasExactlyOneBit(roadtypes) || !HasRoadTypesAvail(company, roadtypes)) return CMD_ERROR; + roadtype = Extract(p2); + if (!ValParamRoadType(roadtype)) return CMD_ERROR; break; case TRANSPORT_RAIL: @@ -380,6 +381,15 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } + /* If this is a road bridge, make sure the roadtype matches. */ + if (transport_type == TRANSPORT_ROAD) { + RoadType start_existing_rt = GetRoadType(tile_start, GetRoadTramType(roadtype)); + RoadType end_existing_rt = GetRoadType(tile_end, GetRoadTramType(roadtype)); + if ((start_existing_rt != roadtype && start_existing_rt != INVALID_ROADTYPE) || (end_existing_rt != roadtype && end_existing_rt != INVALID_ROADTYPE)) { + return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); + } + } + /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */ if (!(flags & DC_QUERY_COST) && IsTileOwner(tile_start, OWNER_TOWN) && GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed && @@ -395,7 +405,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u } /* Do not replace the bridge with the same bridge type. */ - if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || (roadtypes & ~GetRoadTypes(tile_start)) == 0)) { + if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || (GetRoadType(tile_start, GetRoadTramType(roadtype)) == roadtype && GetRoadType(tile_end, GetRoadTramType(roadtype)) == roadtype))) { return_cmd_error(STR_ERROR_ALREADY_BUILT); } @@ -580,21 +590,25 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u case TRANSPORT_ROAD: { if (is_upgrade) SubtractRoadTunnelBridgeInfrastructure(tile_start, tile_end); - auto make_bridge_ramp = [company, owner, is_upgrade, is_new_owner, bridge_type, roadtypes](TileIndex t, DiagDirection d) { - RoadTypes new_roadtypes = roadtypes | GetRoadTypes(t); - RoadTypes prev_roadtypes = IsBridgeTile(t) ? GetRoadTypes(t) : ROADTYPES_NONE; + auto make_bridge_ramp = [company, owner, is_upgrade, is_new_owner, bridge_type, roadtype](TileIndex t, DiagDirection d) { + RoadType road_rt = is_upgrade ? GetRoadTypeRoad(t) : INVALID_ROADTYPE; + RoadType tram_rt = is_upgrade ? GetRoadTypeTram(t) : INVALID_ROADTYPE; + bool hasroad = road_rt != INVALID_ROADTYPE; + bool hastram = tram_rt != INVALID_ROADTYPE; + if (RoadTypeIsRoad(roadtype)) road_rt = roadtype; + if (RoadTypeIsTram(roadtype)) tram_rt = roadtype; if (is_new_owner) { /* Also give unowned present roadtypes to new owner */ - if (HasBit(prev_roadtypes, ROADTYPE_ROAD) && GetRoadOwner(t, ROADTYPE_ROAD) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_ROAD); - if (HasBit(prev_roadtypes, ROADTYPE_TRAM) && GetRoadOwner(t, ROADTYPE_TRAM) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_TRAM); + if (hasroad && GetRoadOwner(t, RTT_ROAD) == OWNER_NONE) hasroad = false; + if (hastram && GetRoadOwner(t, RTT_TRAM) == OWNER_NONE) hastram = false; } - Owner owner_road = HasBit(prev_roadtypes, ROADTYPE_ROAD) ? GetRoadOwner(t, ROADTYPE_ROAD) : company; - Owner owner_tram = HasBit(prev_roadtypes, ROADTYPE_TRAM) ? GetRoadOwner(t, ROADTYPE_TRAM) : company; - MakeRoadBridgeRamp(t, owner, owner_road, owner_tram, bridge_type, d, new_roadtypes, is_upgrade); + Owner owner_road = hasroad ? GetRoadOwner(t, RTT_ROAD) : company; + Owner owner_tram = hastram ? GetRoadOwner(t, RTT_TRAM) : company; + MakeRoadBridgeRamp(t, owner, owner_road, owner_tram, bridge_type, d, road_rt, tram_rt, is_upgrade); if (is_upgrade) { - if (HasBit(roadtypes, ROADTYPE_ROAD)) SetCustomBridgeHeadRoadBits(t, ROADTYPE_ROAD, GetCustomBridgeHeadRoadBits(t, ROADTYPE_ROAD) | DiagDirToRoadBits(d)); - if (HasBit(roadtypes, ROADTYPE_TRAM)) SetCustomBridgeHeadRoadBits(t, ROADTYPE_TRAM, GetCustomBridgeHeadRoadBits(t, ROADTYPE_TRAM) | DiagDirToRoadBits(d)); + if (road_rt != INVALID_ROADTYPE) SetCustomBridgeHeadRoadBits(t, RTT_ROAD, GetCustomBridgeHeadRoadBits(t, RTT_ROAD) | DiagDirToRoadBits(d)); + if (tram_rt != INVALID_ROADTYPE) SetCustomBridgeHeadRoadBits(t, RTT_TRAM, GetCustomBridgeHeadRoadBits(t, RTT_TRAM) | DiagDirToRoadBits(d)); } }; make_bridge_ramp(tile_start, dir); @@ -603,8 +617,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u if (IsRoadCustomBridgeHead(tile_start) || IsRoadCustomBridgeHead(tile_end)) { NotifyRoadLayoutChanged(); } else { - if (HasBit(roadtypes, ROADTYPE_ROAD)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile_start, tile_end, dir, ROADTYPE_ROAD); - if (HasBit(roadtypes, ROADTYPE_TRAM)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile_start, tile_end, dir, ROADTYPE_TRAM); + NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile_start, tile_end, dir, GetRoadTramType(roadtype)); } break; } @@ -639,7 +652,14 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u bridge_len += 2; // begin and end tiles/ramps switch (transport_type) { - case TRANSPORT_ROAD: cost.AddCost(bridge_len * _price[PR_BUILD_ROAD] * 2 * CountBits(roadtypes)); break; + case TRANSPORT_ROAD: { + cost.AddCost(bridge_len * 2 * RoadBuildCost(roadtype)); + if (is_upgrade && DiagDirToRoadBits(GetTunnelBridgeDirection(tile_start)) & GetCustomBridgeHeadRoadBits(tile_start, OtherRoadTramType(GetRoadTramType(roadtype)))) { + cost.AddCost(bridge_len * 2 * RoadBuildCost(GetRoadType(tile_start, OtherRoadTramType(GetRoadTramType(roadtype))))); + } + break; + } + case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break; default: break; } @@ -762,7 +782,7 @@ static inline CommandCost CanBuildChunnel(TileIndex tile, DiagDirection directio * Build Tunnel. * @param start_tile start tile of tunnel * @param flags type of operation - * @param p1 bit 0-5 railtype or roadtypes + * @param p1 bit 0-5 railtype or roadtype * bit 8-9 transport type * @param p2 unused * @param text unused @@ -773,9 +793,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, CompanyID company = _current_company; TransportType transport_type = Extract(p1); - RailType railtype = INVALID_RAILTYPE; - RoadTypes rts = ROADTYPES_NONE; + RoadType roadtype = INVALID_ROADTYPE; _build_tunnel_endtile = 0; switch (transport_type) { case TRANSPORT_RAIL: @@ -784,8 +803,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, break; case TRANSPORT_ROAD: - rts = Extract(p1); - if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(company, rts)) return CMD_ERROR; + roadtype = Extract(p1); + if (!ValParamRoadType(roadtype)) return CMD_ERROR; break; default: return CMD_ERROR; @@ -927,7 +946,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, /* Pay for the rail/road in the tunnel including entrances */ switch (transport_type) { - case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * _price[PR_BUILD_ROAD] * 2); break; + case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break; case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break; default: NOT_REACHED(); } @@ -953,15 +972,12 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company); YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction)); } else { - if (c != nullptr) { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, rts ^ (IsTunnelTile(start_tile) ? GetRoadTypes(start_tile) : ROADTYPES_NONE)) { - c->infrastructure.road[rt] += num_pieces * 2; // A full diagonal road has two road bits. - NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(start_tile, end_tile, direction, rt); - } - } - MakeRoadTunnel(start_tile, company, t->index, direction, rts); - MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), rts); + if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits. + NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(start_tile, end_tile, direction, GetRoadTramType(roadtype)); + RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE; + RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE; + MakeRoadTunnel(start_tile, company, t->index, direction, road_rt, tram_rt); + MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), road_rt, tram_rt); } DirtyCompanyInfrastructureWindows(company); } @@ -982,12 +998,13 @@ static inline CommandCost CheckAllowRemoveTunnelBridge(TileIndex tile) switch (GetTunnelBridgeTransportType(tile)) { case TRANSPORT_ROAD: { - RoadTypes rts = GetRoadTypes(tile); + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); Owner road_owner = _current_company; Owner tram_owner = _current_company; - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + if (road_rt != INVALID_ROADTYPE) road_owner = GetRoadOwner(tile, RTT_ROAD); + if (tram_rt != INVALID_ROADTYPE) tram_owner = GetRoadOwner(tile, RTT_TRAM); /* We can remove unowned road and if the town allows it */ if (road_owner == OWNER_TOWN && _current_company != OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) { @@ -1089,16 +1106,11 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) if (v != nullptr) TryPathReserve(v); } else { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - /* A full diagonal road tile has two road bits. */ - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != nullptr) { - c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; - DirtyCompanyInfrastructureWindows(c->index); - } - NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, GetTunnelBridgeDirection(tile), rt); - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); + UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); + NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, GetTunnelBridgeDirection(tile), RTT_ROAD); + NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, GetTunnelBridgeDirection(tile), RTT_TRAM); delete Tunnel::GetByTile(tile); @@ -1196,9 +1208,8 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) if (IsRoadCustomBridgeHead(tile) || IsRoadCustomBridgeHead(endtile)) { NotifyRoadLayoutChanged(); } else { - RoadTypes roadtypes = GetRoadTypes(tile); - if (HasBit(roadtypes, ROADTYPE_ROAD)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, direction, ROADTYPE_ROAD); - if (HasBit(roadtypes, ROADTYPE_TRAM)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, direction, ROADTYPE_TRAM); + if (HasRoadTypeRoad(tile)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, direction, RTT_ROAD); + if (HasRoadTypeTram(tile)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, direction, RTT_TRAM); } } else { // Aqueduct if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; @@ -1358,19 +1369,95 @@ static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, 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? - * @param head are we drawing bridge head? + * Draws the road and trambits over an already drawn (lower end) of a bridge. + * @param head_tile bridge head tile with roadtype information + * @param x the x of the bridge + * @param y the y of the bridge + * @param z the z of the bridge + * @param offset sprite offset identifying flat to sloped bridge tiles + * @param head are we drawing bridge head? */ -static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bool head) +static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head) { - 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, 96, 99, 102, 100, 101 }; - static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 }; + RoadType road_rt = GetRoadTypeRoad(head_tile); + RoadType tram_rt = GetRoadTypeTram(head_tile); + if (IsRoadCustomBridgeHeadTile(head_tile)) { + RoadBits entrance_bit = DiagDirToRoadBits(GetTunnelBridgeDirection(head_tile)); + if (road_rt != INVALID_ROADTYPE && !(GetCustomBridgeHeadRoadBits(head_tile, RTT_ROAD) & entrance_bit)) road_rt = INVALID_ROADTYPE; + if (tram_rt != INVALID_ROADTYPE && !(GetCustomBridgeHeadRoadBits(head_tile, RTT_TRAM) & entrance_bit)) tram_rt = INVALID_ROADTYPE; + } + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + SpriteID seq_back[4] = { 0 }; + bool trans_back[4] = { false }; + SpriteID seq_front[4] = { 0 }; + bool trans_front[4] = { false }; + + static const SpriteID overlay_offsets[6] = { 0, 1, 11, 12, 13, 14 }; + static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 }; + static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 }; + + if (head || !IsInvisibilitySet(TO_BRIDGES)) { + /* Road underlay takes precendence over tram */ + trans_back[0] = !head && IsTransparencySet(TO_BRIDGES); + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset; + } + } else if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + seq_back[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset; + } else { + seq_back[0] = SPR_TRAMWAY_BRIDGE + offset; + } + } + + /* Draw road overlay */ + trans_back[1] = !head && IsTransparencySet(TO_BRIDGES); + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[1] != 0) seq_back[1] += overlay_offsets[offset]; + } + } + + /* Draw tram overlay */ + trans_back[2] = !head && IsTransparencySet(TO_BRIDGES); + if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[2] != 0) seq_back[2] += overlay_offsets[offset]; + } else if (road_rti != nullptr) { + seq_back[2] = SPR_TRAMWAY_OVERLAY + overlay_offsets[offset]; + } + } + + /* Road catenary takes precendence over tram */ + trans_back[3] = IsTransparencySet(TO_CATENARY); + trans_front[0] = IsTransparencySet(TO_CATENARY); + if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) { + seq_back[3] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE); + seq_front[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[3] == 0 || seq_front[0] == 0) { + seq_back[3] = SPR_TRAMWAY_BASE + back_offsets[offset]; + seq_front[0] = SPR_TRAMWAY_BASE + front_offsets[offset]; + } else { + seq_back[3] += 23 + offset; + seq_front[0] += 23 + offset; + } + } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) { + seq_back[3] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE); + seq_front[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[3] == 0 || seq_front[0] == 0) { + seq_back[3] = SPR_TRAMWAY_BASE + back_offsets[offset]; + seq_front[0] = SPR_TRAMWAY_BASE + front_offsets[offset]; + } else { + seq_back[3] += 23 + offset; + seq_front[0] += 23 + offset; + } + } + } static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 }; static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 }; @@ -1379,28 +1466,25 @@ static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bo /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called * The bounding boxes here are the same as for bridge front/roof */ - if (head || !IsInvisibilitySet(TO_BRIDGES)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, - x, y, size_x[offset], size_y[offset], 0x28, z, - !head && IsTransparencySet(TO_BRIDGES)); - } - - /* Do not draw catenary if it is set invisible */ - if (!IsInvisibilitySet(TO_CATENARY)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE, - x, y, size_x[offset], size_y[offset], 0x28, z, - IsTransparencySet(TO_CATENARY)); + for (uint i = 0; i < lengthof(seq_back); ++i) { + if (seq_back[i] != 0) { + AddSortableSpriteToDraw(seq_back[i], PAL_NONE, + x, y, size_x[offset], size_y[offset], 0x28, z, + trans_back[i]); + } } /* Start a new SpriteCombine for the front part */ EndSpriteCombine(); StartSpriteCombine(); - /* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */ - if (!IsInvisibilitySet(TO_CATENARY)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE, - x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, - IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]); + for (uint i = 0; i < lengthof(seq_front); ++i) { + if (seq_front[i] != 0) { + AddSortableSpriteToDraw(seq_front[i], PAL_NONE, + x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, + trans_front[i], + front_bb_offset_x[offset], front_bb_offset_y[offset]); + } } } @@ -1586,20 +1670,37 @@ static void DrawTile_TunnelBridge(TileInfo *ti) DrawGroundSprite(image, PAL_NONE); if (transport_type == TRANSPORT_ROAD) { - 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][tunnelbridge_direction], PAL_NONE); - - /* Do not draw wires if they are invisible */ - if (!IsInvisibilitySet(TO_CATENARY)) { - catenary = true; - StartSpriteCombine(); - AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? 1 : 0; + + DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset); + + /* Road catenary takes precendence over tram */ + SpriteID catenary_sprite_base = 0; + if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) { + catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_CATENARY_FRONT); + if (catenary_sprite_base == 0) { + catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES; + } else { + catenary_sprite_base += 19; + } + } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) { + catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_CATENARY_FRONT); + if (catenary_sprite_base == 0) { + catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES; + } else { + catenary_sprite_base += 19; } } + + if (catenary_sprite_base != 0) { + catenary = true; + StartSpriteCombine(); + AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); + } } else { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); if (rti->UsesOverlay()) { @@ -1747,20 +1848,18 @@ static void DrawTile_TunnelBridge(TileInfo *ti) AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z); if (transport_type == TRANSPORT_ROAD) { - RoadTypes rts = GetRoadTypes(ti->tile); - - if (HasBit(rts, ROADTYPE_TRAM)) { - uint offset = tunnelbridge_direction; - int z = ti->z; - if (ti->tileh != SLOPE_FLAT) { - offset = (offset + 1) & 1; - z += TILE_HEIGHT; - } else { - offset += 2; - } - /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD), true); + uint offset = tunnelbridge_direction; + int z = ti->z; + if (ti->tileh != SLOPE_FLAT) { + offset = (offset + 1) & 1; + z += TILE_HEIGHT; + } else { + offset += 2; } + + /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ + DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true); + EndSpriteCombine(); } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); @@ -1949,23 +2048,8 @@ void DrawBridgeMiddle(const TileInfo *ti) psid++; if (transport_type == TRANSPORT_ROAD) { - const RoadTypes rts = GetRoadTypes(rampsouth); - - bool has_tram = HasBit(rts, ROADTYPE_TRAM); - bool has_road = HasBit(rts, ROADTYPE_ROAD); - if (IsRoadCustomBridgeHeadTile(rampsouth)) { - RoadBits entrance_bit = DiagDirToRoadBits(GetTunnelBridgeDirection(rampsouth)); - has_tram = has_tram && (GetCustomBridgeHeadRoadBits(rampsouth, ROADTYPE_TRAM) & entrance_bit); - has_road = has_road && (GetCustomBridgeHeadRoadBits(rampsouth, ROADTYPE_ROAD) & entrance_bit); - } - - if (has_tram) { - /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, has_road, false); - } else { - EndSpriteCombine(); - StartSpriteCombine(); - } + /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ + DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false); } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth)); if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) { @@ -2097,9 +2181,20 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } /* Is there a mix of owners? */ if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || @@ -2135,7 +2230,9 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) } } } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) { - td->road_speed = GetBridgeSpec(GetBridgeType(tile))->speed; + uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed; + if (road_rt != INVALID_ROADTYPE && (td->road_speed == 0 || spd < td->road_speed)) td->road_speed = spd; + if (tram_rt != INVALID_ROADTYPE && (td->tram_speed == 0 || spd < td->tram_speed)) td->tram_speed = spd; } } @@ -2193,15 +2290,13 @@ extern const TrackBits _road_trackbits[16]; static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { TransportType transport_type = GetTunnelBridgeTransportType(tile); - if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0; + if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0; DiagDirection dir = GetTunnelBridgeDirection(tile); if (side != INVALID_DIAGDIR && side == dir) return 0; if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) { - TrackBits bits = TRACK_BIT_NONE; - if (sub_mode & ROADTYPES_TRAM) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)]; - if (sub_mode & ROADTYPES_ROAD) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD)]; + TrackBits bits = _road_trackbits[GetCustomBridgeHeadRoadBits(tile, (RoadTramType)sub_mode)]; return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE); } return CombineTrackStatus(TrackBitsToTrackdirBits(mode == TRANSPORT_RAIL ? GetTunnelBridgeTrackBits(tile) : DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE); @@ -2212,14 +2307,14 @@ static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, const uint middle_len = 2 * GetTunnelBridgeLength(begin, end) * TUNNELBRIDGE_TRACKBIT_FACTOR; const uint len = middle_len + (4 * TUNNELBRIDGE_TRACKBIT_FACTOR); - /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(begin)) { - Company * const c = Company::GetIfValid(GetRoadOwner(begin, rt)); + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(begin, rtt); + if (rt == INVALID_ROADTYPE) continue; + Company * const c = Company::GetIfValid(GetRoadOwner(begin, rtt)); if (c != nullptr) { uint infra = 0; if (IsBridge(begin)) { - const RoadBits bits = GetCustomBridgeHeadRoadBits(begin, rt); + const RoadBits bits = GetCustomBridgeHeadRoadBits(begin, rtt); infra += CountBits(bits) * TUNNELBRIDGE_TRACKBIT_FACTOR; if (bits & DiagDirToRoadBits(GetTunnelBridgeDirection(begin))) { infra += middle_len; @@ -2234,12 +2329,14 @@ static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, } } } - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(end)) { - Company * const c = Company::GetIfValid(GetRoadOwner(end, rt)); + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(end, rtt); + if (rt == INVALID_ROADTYPE) continue; + Company * const c = Company::GetIfValid(GetRoadOwner(end, rtt)); if (c != nullptr) { uint infra = 0; if (IsBridge(end)) { - const RoadBits bits = GetCustomBridgeHeadRoadBits(end, rt); + const RoadBits bits = GetCustomBridgeHeadRoadBits(end, rtt); infra += CountBits(bits) * TUNNELBRIDGE_TRACKBIT_FACTOR; } if (add) { @@ -2318,13 +2415,13 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner /* Only execute this for one of the two ends */ SubtractRoadTunnelBridgeInfrastructure(tile, other_end); - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + if (GetRoadOwner(tile, rtt) == old_owner) { + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } - if (GetRoadOwner(other_end, rt) == old_owner) { - SetRoadOwner(other_end, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + if (GetRoadOwner(other_end, rtt) == old_owner) { + SetRoadOwner(other_end, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } @@ -2497,8 +2594,8 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti RoadVehicle *rv = RoadVehicle::From(v); if (IsRoadCustomBridgeHeadTile(tile)) { RoadBits bits = ROAD_NONE; - if (rv->compatible_roadtypes & ROADTYPES_TRAM) bits |= GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM); - if (rv->compatible_roadtypes & ROADTYPES_ROAD) bits |= GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD); + if (HasRoadTypeRoad(tile) && rv->compatible_roadtypes & GetRoadTypeRoad(tile)) bits |= GetCustomBridgeHeadRoadBits(tile, RTT_ROAD); + if (HasRoadTypeTram(tile) && rv->compatible_roadtypes & GetRoadTypeTram(tile)) bits |= GetCustomBridgeHeadRoadBits(tile, RTT_TRAM); if (!(bits & DiagDirToRoadBits(GetTunnelBridgeDirection(tile)))) return VETSB_CONTINUE; } rv->cur_image_valid_dir = INVALID_DIR; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index c92880e7a9..3d6cd86e01 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2457,7 +2457,7 @@ UnitID GetFreeUnitNumber(VehicleType type) * @return true if there is any reason why you may build * the infrastructure for the given vehicle type */ -bool CanBuildVehicleInfrastructure(VehicleType type) +bool CanBuildVehicleInfrastructure(VehicleType type, byte subtype) { assert(IsCompanyBuildableVehicleType(type)); @@ -2470,7 +2470,10 @@ bool CanBuildVehicleInfrastructure(VehicleType type) if (!HasAnyRailtypesAvail(_local_company)) return false; max = _settings_game.vehicle.max_trains; break; - case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break; + case VEH_ROAD: + if (!HasAnyRoadTypesAvail(_local_company, (RoadTramType)subtype)) return false; + max = _settings_game.vehicle.max_roadveh; + break; case VEH_SHIP: max = _settings_game.vehicle.max_ships; break; case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break; default: NOT_REACHED(); @@ -2481,6 +2484,7 @@ bool CanBuildVehicleInfrastructure(VehicleType type) /* Can we actually build the vehicle type? */ const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, type) { + if (type == VEH_ROAD && GetRoadTramType(e->u.road.roadtype) != (RoadTramType)subtype) continue; if (HasBit(e->company_avail, _local_company)) return true; } return false; @@ -2489,6 +2493,7 @@ bool CanBuildVehicleInfrastructure(VehicleType type) /* We should be able to build infrastructure when we have the actual vehicle type */ const Vehicle *v; FOR_ALL_VEHICLES(v) { + if (type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != (RoadTramType)subtype) continue; if (v->owner == _local_company && v->type == type) return true; } diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 3baec855b4..82229beddf 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -72,7 +72,7 @@ UnitID GetFreeUnitNumber(VehicleType type); void VehicleEnterDepot(Vehicle *v); -bool CanBuildVehicleInfrastructure(VehicleType type); +bool CanBuildVehicleInfrastructure(VehicleType type, byte subtype = 0); /** Position information of a vehicle after it moved */ struct GetNewVehiclePosResult { diff --git a/src/viewport_type.h b/src/viewport_type.h index 7892b3199c..0697f8d11d 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -138,6 +138,7 @@ enum ViewportDragDropSelectionProcess { DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks) DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses) DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks) + DDSP_CONVERT_ROAD, ///< Road conversion }; diff --git a/src/widgets/autoreplace_widget.h b/src/widgets/autoreplace_widget.h index 4b761ca45d..8432b1a7f2 100644 --- a/src/widgets/autoreplace_widget.h +++ b/src/widgets/autoreplace_widget.h @@ -34,9 +34,11 @@ enum ReplaceVehicleWidgets { WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE, ///< Stop Replacing button. + /* Train/road only widgets */ + WID_RV_RAIL_ROAD_TYPE_DROPDOWN, ///< Dropdown menu about the rail/roadtype. + /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, ///< Dropdown to select engines and/or wagons. - WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; diff --git a/src/widgets/company_widget.h b/src/widgets/company_widget.h index f5b9e65030..54f6c6121f 100644 --- a/src/widgets/company_widget.h +++ b/src/widgets/company_widget.h @@ -180,6 +180,8 @@ enum CompanyInfrastructureWidgets { WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT, ///< Count of road. + WID_CI_TRAM_DESC, ///< Description of tram. + WID_CI_TRAM_COUNT, ///< Count of tram. WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC, ///< Description of station. diff --git a/src/widgets/road_widget.h b/src/widgets/road_widget.h index f022489e53..60068317ab 100644 --- a/src/widgets/road_widget.h +++ b/src/widgets/road_widget.h @@ -15,6 +15,7 @@ /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ + WID_ROT_CAPTION, ///< Caption of the window WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD, ///< Autorail. @@ -26,6 +27,7 @@ enum RoadToolbarWidgets { WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE, ///< Remove road. + WID_ROT_CONVERT_ROAD, ///< Convert road. }; /** Widgets of the #BuildRoadDepotWindow class. */ diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index 5f0c1b5a4f..5b9d1e1568 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -39,6 +39,7 @@ enum ToolbarNormalWidgets { WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools WID_TN_RAILS = WID_TN_BUILDING_TOOLS_START, ///< Rail building menu. WID_TN_ROADS, ///< Road building menu. + WID_TN_TRAMS, ///< Tram building menu. WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE, ///< Landscaping toolbar. @@ -66,6 +67,7 @@ enum ToolbarEditorWidgets { WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS, ///< Road building menu. + WID_TE_TRAMS, ///< Tram building menu. WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS, ///< Sign building.
        OOOX XXXX XXXX XXXX XXXX XXXX XXXX XXXXOOOO OOOOOOXX XXXX XXXX XXXX OOXX XOOOXXXO XXXXOOOO OOOO OOOO OOOOOOXO XXXXOOOO XXXX XXOO OOOO
        level crossingOOOO OOOO XXXX OOPX OOXX XOOOXXXX XXXXOOOO OOOO OOXX XXXXOOXX XXXXOOOO XXXX XXXX XXXX
        road depotOOOX XXXX -inherit- XXXX OOOOOOOO OOOO-inherit- XXOO OOXX OOOO OOOOXXXO XXXXOOOO OOOO OOOO OOOOOOXO XXXX-inherit-
        3OXXX XXXX -inherit- XXXX OOOOOOOO OOOOOOXX XXXX ~~~~ ~XXX OOXX XOOOXXOX XXXXOOOO OOOO OOOO OOOOOOOX XXXXOOOO XXXX XXOO OOOO
        dockOOOX XXXX PPPP PPPP PPPP PPPP XXXX OOOOOOOO OOOOXPPX XXXXOOXX XXXXXOOX XXXX PPOO OOPPXXXX XXXXOOOO OOOO OOXX XXXXOOXX XXXXOOOO XXXX XXXX XXXX
        bridge ramp-inherit- PPPP PPPP PPPP PPPP -inherit-OOPP PPPPOOPP PPPP -inherit- PPXX XXPP -inherit-OOOO PPPP PPXX XXXXOOOO PPPP PPXX XXXX
        A