diff --git a/.ottdrev-vc b/.ottdrev-vc index ba4e9b4955..3e9586e6f9 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.6.0 27410 0 jgrpp-0.6.0 -7e2be8b9c405340ad95cf1cb2ae3299a00ad9bde87001c17da1216ab75dab5e0 - +jgrpp-0.7.0 27415 0 jgrpp-0.7.0 +788f8c0cf7000f20953ac49e57bb799b1c75c7774d9b7aeb9b188fe3e415a7c9 - diff --git a/README.md b/README.md index 33b95e057b..cd1726462f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.6.0 +## JGR's Patchpack version 0.7.0 This is a collection of patches applied to [OpenTTD](http://www.openttd.org/) @@ -41,9 +41,10 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog. As of v0.6.0, add a mode to show restricted signals. * Departure boards: [imported](https://www.tt-forums.net/viewtopic.php?f=33&t=49956) - Fixed departure boards with orders with timetabled 0 travel times, e.g. those with depot service orders. - Fixed memory leak. - Made modifications to work with day length greater than 1. + * Fixed departure boards with orders with timetabled 0 travel times, e.g. those with depot service orders. + * Fixed memory leak. + * Made modifications to work with day length greater than 1. + * As of v0.7.0, fixed a multiplayer desync caused by the timetable rounding depending on the client time display mode setting. * Town cargo generation factor: [imported](http://www.tt-forums.net/viewtopic.php?t=46399) @@ -70,7 +71,8 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog. * Auto timetabling: Bias timetable adjustment to favour negative adjustments; this is to avoid positive feedback between congestion delays and increased timetable length. Reduce jam detection threshold. * Auto separation: Fix handling of non-station orders (e.g. waypoints and depots). Add setting to scale vehicle lateness adjustments. No longer set vehicle lateness to 0 if separation fails, instead leave it as it was. * Timetable GUI: Allow clearing of timetable time fields which are at 0. Allow explicitly setting timetable time fields to 0 without clearing them. - * Add a company setting to enable automatic timetabling for new vehicles (added in v0.4.0). + * Add a company setting to enable automatic timetabling for new vehicles (added in v0.4.0). + * As of v0.7.0, the setting to scale vehicle lateness adjustments is a company setting. * Vehicle repair cost: [imported](http://www.tt-forums.net/viewtopic.php?f=33&t=45642) @@ -91,7 +93,8 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog. * As of v0.5.0, fix status bar date when time in minutes and show date with time are both on. * Order occupancy - Add column to orders GUI to show occupancy running average. + Add column to orders GUI to show occupancy running average. + As of v0.7.0, the smoothness setting is company setting. * Servicing Send vehicles which need auto-renewing due to age for servicing, even if breakdowns are off and no servicing if no breakdowns is on. @@ -128,6 +131,8 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog. * Pause on savegame load if ctrl key is pressed. (added in v0.6.0) +* Reverse at waypoint orders (added in v0.7.0) + * Save/load and savegame format changes * Various changes to improve handling of savegames which use features not in trunk. * Savegames from this patchpack are not loadable in trunk. @@ -139,6 +144,10 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog. * Changes to the crash log (added in v0.5.0) Enable stack traces on MinGW, try to demangle C++ symbol names, try to use libbfd for better symbol lookup, handle SIGSEGV while backtracing. +* Multiplayer desync fixes/changes + * Fix YAPF pathfinder desync issue involving rail track type changes which where only passable by a subset of vehicles (trunk bug). (added in v0.6.0) + * Logging: Various changes and improvements to desync-related logging and debugging, see changelog for details. + #### Caveats for loading savegames from the [Spring 2013 Patch Pack](http://www.tt-forums.net/viewtopic.php?f=33&t=66892): * This is not guaranteed to be bug free diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index d69598f57a..977a8df62c 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,13 @@ * * * +### v0.7.0 (2015-10-29) +* Fix timetable rounding depending on the client time display mode setting, which caused desyncs in multiplayer (departure boards patch bug). +* Add reverse at waypoint orders. +* Change the order occupancy smoothness and automated timetables vehicle lateness adjustment scale settings, to be company settings. +* Fix compilation on some compilers/platforms. +* Bump trunk base from r27410 to r27415 + ### v0.6.0 (2015-10-17) * Zoning: Add mode to show restricted signals. * Pause on savegame load if ctrl key is pressed. diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 9316526c11..351989dd4a 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -310,6 +310,7 @@ + @@ -430,12 +431,16 @@ + + + + @@ -638,6 +643,7 @@ + @@ -709,6 +715,7 @@ + @@ -768,6 +775,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index f67f313219..be295c10b8 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -159,6 +159,9 @@ Source Files + + Source Files + Source Files @@ -519,6 +522,9 @@ Header Files + + Header Files + Header Files @@ -537,6 +543,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + Header Files @@ -1143,6 +1158,9 @@ Header Files + + Header Files + Header Files @@ -1356,6 +1374,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1533,6 +1554,9 @@ Widgets + + Widgets + Widgets diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index b82aba741c..7698bc0497 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -327,6 +327,7 @@ + @@ -348,6 +349,7 @@ + @@ -374,6 +376,7 @@ + @@ -383,6 +386,8 @@ + + @@ -443,12 +448,16 @@ + + + + @@ -498,6 +507,7 @@ + @@ -574,6 +584,9 @@ + + + @@ -599,11 +612,13 @@ + + @@ -645,6 +660,7 @@ + @@ -677,6 +693,7 @@ + @@ -715,6 +732,7 @@ + @@ -740,6 +758,7 @@ + @@ -762,6 +781,7 @@ + @@ -772,6 +792,7 @@ + @@ -801,6 +822,7 @@ + @@ -829,6 +851,7 @@ + @@ -845,6 +868,7 @@ + @@ -873,6 +897,7 @@ + @@ -886,6 +911,7 @@ + @@ -899,6 +925,7 @@ + @@ -1290,6 +1317,10 @@ + + + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 0b6dc573b4..be295c10b8 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -159,6 +159,9 @@ Source Files + + Source Files + Source Files @@ -222,6 +225,9 @@ Source Files + + Source Files + Source Files @@ -300,6 +306,9 @@ Source Files + + Source Files + Source Files @@ -327,6 +336,12 @@ Source Files + + Source Files + + + Source Files + Source Files @@ -507,6 +522,9 @@ Header Files + + Header Files + Header Files @@ -525,6 +543,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + Header Files @@ -672,6 +699,9 @@ Header Files + + Header Files + Header Files @@ -900,6 +930,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + Header Files @@ -975,6 +1014,9 @@ Header Files + + Header Files + Header Files @@ -990,6 +1032,9 @@ Header Files + + Header Files + Header Files @@ -1113,6 +1158,9 @@ Header Files + + Header Files + Header Files @@ -1209,6 +1257,9 @@ Header Files + + Header Files + Core Source Code @@ -1323,6 +1374,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1398,6 +1452,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1464,6 +1521,9 @@ GUI Source Code + + GUI Source Code + Widgets @@ -1494,6 +1554,9 @@ Widgets + + Widgets + Widgets @@ -1581,6 +1644,9 @@ Widgets + + Widgets + Widgets @@ -1665,6 +1731,9 @@ Command handlers + + Command handlers + Command handlers @@ -1713,6 +1782,9 @@ Command handlers + + Command handlers + Save/Load handlers @@ -1797,6 +1869,9 @@ Save/Load handlers + + Save/Load handlers + Save/Load handlers @@ -1836,6 +1911,9 @@ Save/Load handlers + + Save/Load handlers + Save/Load handlers @@ -1875,6 +1953,9 @@ Tables + + Tables + Tables @@ -3048,6 +3129,18 @@ Threading + + Threading + + + Threading + + + Threading + + + Threading + diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 1f690158dd..9998f812c2 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -998,6 +998,10 @@ RelativePath=".\..\src\crashlog.h" > + + @@ -1842,6 +1846,10 @@ RelativePath=".\..\src\town.h" > + + @@ -2378,6 +2386,10 @@ RelativePath=".\..\src\widgets\date_widget.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 86ec976b31..5c584dbd44 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -995,6 +995,10 @@ RelativePath=".\..\src\crashlog.h" > + + @@ -1839,6 +1843,10 @@ RelativePath=".\..\src\town.h" > + + @@ -2375,6 +2383,10 @@ RelativePath=".\..\src\widgets\date_widget.h" > + + diff --git a/source.list b/source.list index 275ebf1569..d43b904297 100644 --- a/source.list +++ b/source.list @@ -535,6 +535,7 @@ widgets/cheat_widget.h widgets/company_widget.h widgets/console_widget.h widgets/date_widget.h +widgets/departures_widget.h widgets/depot_widget.h widgets/dock_widget.h widgets/dropdown.cpp diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index cf1836e9b0..17061443d9 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -820,7 +820,7 @@ static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, /* We are northwest or southeast of the airport */ dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE; } - dir = ChangeDiagDir(dir, (DiagDirDiff)ReverseDiagDir(DirToDiagDir(rotation))); + dir = ChangeDiagDir(dir, DiagDirDifference(DIAGDIR_NE, DirToDiagDir(rotation))); return apc->entry_points[dir]; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 4a6a7d1b32..eb99cb9359 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -1768,7 +1768,8 @@ struct CompanyInfrastructureWindow : Window if (this->railtypes != RAILTYPES_NONE) { /* Draw name of each valid railtype. */ - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { if (HasBit(this->railtypes, rt)) { SetDParam(0, GetRailTypeInfo(rt)->strings.name); DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); @@ -1785,7 +1786,8 @@ struct CompanyInfrastructureWindow : Window case WID_CI_RAIL_COUNT: { /* Draw infrastructure count for each valid railtype. */ uint32 rail_total = c->infrastructure.GetRailTotal(); - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { if (HasBit(this->railtypes, rt)) { this->DrawCountLine(r, y, c->infrastructure.rail[rt], RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); } diff --git a/src/direction_func.h b/src/direction_func.h index 8889485842..12aee58639 100644 --- a/src/direction_func.h +++ b/src/direction_func.h @@ -61,11 +61,11 @@ static inline Direction ReverseDir(Direction d) /** - * Calculate the difference between to directions + * Calculate the difference between two directions * * @param d0 The first direction as the base * @param d1 The second direction as the offset from the base - * @return The difference how the second directions drifts of the first one. + * @return The difference how the second direction drifts of the first one. */ static inline DirDiff DirDifference(Direction d0, Direction d1) { @@ -79,7 +79,7 @@ static inline DirDiff DirDifference(Direction d0, Direction d1) /** * Applies two differences together * - * This function adds two differences together and return the resulting + * This function adds two differences together and returns the resulting * difference. So adding two DIRDIFF_REVERSE together results in the * DIRDIFF_SAME difference. * @@ -123,6 +123,20 @@ static inline DiagDirection ReverseDiagDir(DiagDirection d) return (DiagDirection)(2 ^ d); } +/** + * Calculate the difference between two DiagDirection values + * + * @param d0 The first direction as the base + * @param d1 The second direction as the offset from the base + * @return The difference how the second direction drifts of the first one. + */ +static inline DiagDirDiff DiagDirDifference(DiagDirection d0, DiagDirection d1) +{ + assert(IsValidDiagDirection(d0)); + assert(IsValidDiagDirection(d1)); + /* Cast to uint so compiler can use bitmask. Result can never be negative. */ + return (DiagDirDiff)((uint)(d0 - d1) % 4); +} /** * Applies a difference on a DiagDirection diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 8bf24d9854..1e95782d1e 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -548,18 +548,21 @@ public: group_vehicles++; } - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + 1, STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK); + const int left_edge = r.left + WD_FRAMERECT_LEFT + 8; + const int right_edge = r.right - WD_FRAMERECT_RIGHT - 8; + + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + 1, STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK); SetDParam(0, this_year); - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + 1, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + 1, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + 2, STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK); + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + 2, STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK); SetDParam(0, last_year); - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + 2, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + 2, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + 3, STR_GROUP_OCCUPANCY, TC_BLACK); + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + 3, STR_GROUP_OCCUPANCY, TC_BLACK); if (group_vehicles > 0) { SetDParam(0, occupancy / group_vehicles); - DrawString(r.left + WD_FRAMERECT_LEFT + 8, r.right - WD_FRAMERECT_RIGHT - 16, r.top + WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + 3, STR_GROUP_OCCUPANCY_VALUE, TC_BLACK, SA_RIGHT); + DrawString(left_edge, right_edge, r.top + WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + 3, STR_GROUP_OCCUPANCY_VALUE, TC_BLACK, SA_RIGHT); } break; diff --git a/src/lang/english.txt b/src/lang/english.txt index f907a1812d..4c8e1cc981 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1453,8 +1453,8 @@ STR_CONFIG_SETTING_TIMETABLE_START_TEXT_ENTRY :Enter timetable STR_CONFIG_SETTING_TIMETABLE_START_TEXT_ENTRY_HELPTEXT :Select whether timetable start times may be entered as text if time is being shown in minutes STR_CONFIG_SETTING_TIMETABLE_SEPARATION :Use timetable to ensure vehicle separation: {STRING2} STR_CONFIG_SETTING_TIMETABLE_SEPARATION_HELPTEXT :Select whether to ensure separation of vehicles when using automatic timetables -STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE :Vehicle separation factor: {STRING2} -STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE_HELPTEXT :How much of the vehicle separation timetable change to apply at each step +STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE :Auto timetable vehicle separation factor: {STRING2} +STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE_HELPTEXT :How much of the vehicle separation auto timetable change to apply at each step STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2} @@ -4221,6 +4221,9 @@ STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Select w STR_ORDER_DROP_REFIT_AUTO :Fixed cargo STR_ORDER_DROP_REFIT_AUTO_ANY :Available cargo +STR_ORDER_REVERSE :{BLACK}Reverse +STR_ORDER_REVERSE_TOOLTIP :{BLACK}Change the reversing behaviour of the highlighted order. + STR_ORDER_SERVICE :{BLACK}Service STR_ORDER_DROP_GO_ALWAYS_DEPOT :Always go STR_ORDER_DROP_SERVICE_DEPOT :Service if needed @@ -4299,6 +4302,8 @@ STR_ORDERS_OCCUPANCY_PERCENT :{NUM}% # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} +STR_ORDER_GO_TO_WAYPOINT_REVERSE :Go via and reverse at {WAYPOINT} +STR_ORDER_GO_NON_STOP_TO_WAYPOINT_REVERSE :Go non-stop via and reverse at {WAYPOINT} STR_ORDER_SERVICE_AT :Service at STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at diff --git a/src/lang/korean.txt b/src/lang/korean.txt index fe1d2cc881..a727b5233c 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -2174,7 +2174,7 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :게임이 아 STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :게임이 아직 일시 정지된 상태입니다. ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :게임이 아직 일시 정지된 상태입니다. ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :게임이 재개되었습니다. ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :충분한 플레이어가 없습니다 +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :플레이하는 사람 수 STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :접속자와 연결중 STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :수동 STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :게임 스크립트 diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 3b8cb42b21..ff69eecb75 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -434,7 +434,7 @@ STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Fundar nueva in ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Construcción de ferrocarril -STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Construcción ferrocarril eléctrico +STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Construcción de ferrocarril eléctrico STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Construcción de monorraíl STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Construcción de maglev ############ range ends here @@ -625,7 +625,7 @@ STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Préstam STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Cantidad de vehículos que obtuvieron beneficios el año pasado. Incluye vehículos de carretera, trenes, barcos y aeronaves -STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Cantidad de partes de estación que han tenido servicio. Las estaciones de tren, paradas de autobus, aeropuertos y demás son contabilizadas por separado incluso si pertenecen a la misma estación +STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Cantidad de partes de estación que han tenido servicio. Las estaciones de tren, paradas de autobús, aeropuertos y demás son contabilizadas por separado incluso si pertenecen a la misma estación STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Beneficio del vehículo con menores ingresos (de entre todos los vehículos con más de 2 años) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Cantidad de dinero ganado en el trimestre con el beneficio más bajo de los pasados 12 trimestres STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Cantidad de dinero ganado en el trimestre con el beneficio más alto de los pasados 12 trimestres @@ -656,15 +656,15 @@ STR_MUSIC_TRACK :{TINY_FONT}{BLA STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Título STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Mezclar STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programa -STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Pasar a pista anterior de la selección -STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Pasar a siguiente pista de la selección +STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Saltar a la pista anterior de la selección +STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Saltar a la siguiente pista de la selección STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Detener música STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Comenzar música STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Mueva los cursores para fijar volumen de música y efectos STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Seleccionar programa 'todas las pistas' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Seleccionar programa 'estilo antiguo' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Seleccionar programa 'estilo moderno' -STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Elegir el programa musical de estilo 'Ezy Street' +STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Seleccionar programa 'estilo Ezy Street' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Seleccionar programa 'Personal 1' (definido por el usuario) STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Seleccionar programa 'Personal 2' (definido por el usuario) STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Encender/apagar mezclador @@ -717,7 +717,7 @@ STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Mostrar STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Mostrar propietarios de terrenos en el mapa STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Click en un tipo de industria para mostrarlo/ocultarlo. Ctrl+Click oculta todos los tipos excepto el seleccionado. Ctrl+Click de nuevo en el mismo tipo muestra todos los tipos de industrias STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Click en una empresa para mostrar/ocultar sus propiedades. Ctrl+Click oculta todas las empresas excepto la seleccionada. Ctrl+Click de nuevo en la misma empresa muestra todas las empresas -STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Un Click en una carga permite activar o desactivar su visualización. Ctrl+Click deshabilita todas las cargas excepto la seleccionada. Un segundo Ctrl+Click habilita la visualización de todos los tipos de carga +STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click en una carga permite activar o desactivar su visualización. Ctrl+Click deshabilita todas las cargas excepto la seleccionada. Un segundo Ctrl+Click habilita la visualización de todos los tipos de carga STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Carreteras STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Ferrocarriles @@ -942,7 +942,7 @@ STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Francés STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Alemán STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Inglés (Adicional) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latinoamericano -STR_GAME_OPTIONS_TOWN_NAME_SILLY :Tontos +STR_GAME_OPTIONS_TOWN_NAME_SILLY :Absurdos STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Sueco STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Holandés STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finlandés @@ -991,7 +991,7 @@ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Tamaño cuádru STR_GAME_OPTIONS_BASE_GRF :{BLACK}Conjunto de gráficos base STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Selecciona el conjunto de gráficos base a usar STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} fichero{P "" s} perdido{P "" s} o corrupto{P "" s} -STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Información adicional acerca de este fichero de gráficos +STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Información adicional sobre el set de gráficos base STR_GAME_OPTIONS_BASE_SFX :{BLACK}Conjunto de sonidos base STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Seleccionar conjunto de sonidos base a emplear @@ -1820,14 +1820,14 @@ STR_LIVERY_PANEL_TOOLTIP :{BLACK}Seleccio STR_LIVERY_DEFAULT :Estación normal STR_LIVERY_STEAM :Locomotora a Vapor -STR_LIVERY_DIESEL :Locomotora Diesel +STR_LIVERY_DIESEL :Locomotora Diésel STR_LIVERY_ELECTRIC :Locomotora Eléctrica STR_LIVERY_MONORAIL :Locomotora Monorraíl STR_LIVERY_MAGLEV :Locomotora Maglev STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Vagón Pasajeros (Vapor) -STR_LIVERY_PASSENGER_WAGON_DIESEL :Vagón Pasajeros (Diesel) +STR_LIVERY_PASSENGER_WAGON_DIESEL :Vagón Pasajeros (Diésel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Vagón Pasajeros (Eléctrico) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Vagón Pasajeros (Monorraíl) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Vagón Pasajeros (Maglev) @@ -2248,7 +2248,7 @@ STR_CONTENT_TYPE_GS_LIBRARY :Librería SJ # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Descargando contenido... -STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Solicitando ficheros... +STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Solicitando archivos... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Descargando {STRING} ({NUM} de {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Descarga completada STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} de {BYTES} descargadas ({NUM} %) @@ -2257,8 +2257,8 @@ STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}No es posible conectarse al servidor de contenidos... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Descarga errónea... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... conexión perdida -STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... no se puede escribir en el fichero -STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}No ha sido posible descomprimir el fichero descargado +STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... no se puede escribir en el archivo +STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}No ha sido posible descomprimir el archivo descargado STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Gráficos no encontrados STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD necesita gráficos para funcionar pero no se pudo encontrar ninguno. ¿Desea permitir que OpenTTD descargue e instale dichos gráficos? @@ -2802,8 +2802,8 @@ STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Borrar STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Borrar la programación seleccionada STR_NEWGRF_SETTINGS_ADD :{BLACK}Añadir STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Añade el NewGRF seleccionado a tu configuración -STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Actualizar ficheros -STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Actualiza la lista de ficheros NewGRF disponibles +STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Actualizar archivos +STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Actualiza la lista de archivos NewGRF disponibles STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Retirar STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Retirar el NewGRF seleccionado de la lista STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Mover Arriba @@ -2812,7 +2812,7 @@ STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Mover Ab STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Mueve el NewGRF seleccionado abajo en la lista STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Actualiza STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Utiliza las versiones más nuevas de los archivos NewGRF que dispongan de diversas versiones instaladas -STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Una lista de los ficheros NewGRF instalados +STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Una lista de los archivos NewGRF instalados STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Establecer parámetros STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Mostrar parámetros @@ -2823,7 +2823,7 @@ STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Aplicar STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Encontrar contenido que falta en línea STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Comprobar si el contenido que falta puede ser encontrado en línea -STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Fichero: {SILVER}{STRING} +STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Archivo: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Versión: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Mín. versión compatible: {SILVER}{NUM} @@ -2832,7 +2832,7 @@ STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Paleta: STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parámetros: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}No tiene información disponible -STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Fichero no encontrado +STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Archivo no encontrado STR_NEWGRF_SETTINGS_DISABLED :{RED}Desactivado STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Incompatible con esta versión de OpenTTD @@ -2918,18 +2918,18 @@ STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}¡Precau STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Se van a modificar los NewGRF de una partida ya comenzada. Esto puede provocar un error fatal en OpenTTD o romper la partida.{}No se deben crear reportes de bugs por problemas causados por esta acción.{}¿Está completamente seguro de esto? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}No se puede añadir: GRF ID duplicado -STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Fichero no encontrado (GRF compatible cargado) +STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Archivo no encontrado (GRF compatible cargado) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}No se puede añadir fichero: Límite de ficheros NewGRF alcanzado -STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}GRF(s) compatibles cargados para ficheros que faltan -STR_NEWGRF_DISABLED_WARNING :{WHITE}Fichero(s) GRF no encontrados han sido desactivados -STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Fichero(s) GRF no encontrados +STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}GRF(s) compatibles cargados para archivos que faltan +STR_NEWGRF_DISABLED_WARNING :{WHITE}Archivo(s) GRF no encontrados han sido desactivados +STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Archivo(s) GRF no encontrados STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Quitar la pausa puede hacer que se cierre OpenTTD. No notifique este error.{}¿Desea realmente quitar la pausa? # NewGRF status STR_NEWGRF_LIST_NONE :Ninguno STR_NEWGRF_LIST_ALL_FOUND :Todos los ficheros presentes -STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Ficheros compatibles encontrados +STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Archivos compatibles encontrados STR_NEWGRF_LIST_MISSING :{RED}Ficheros que faltan # NewGRF 'it's broken' warnings @@ -3921,7 +3921,7 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Fecha de STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Selecciona una fecha como punto de partida de este horario. Ctrl+Click permite fijar el punto de partida de este horario y distribuye todos los vehículos que lo compartan siempre y cuando el horario esté completo STR_TIMETABLE_CHANGE_TIME :{BLACK}Cambiar Horario -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Cambia la cantidad de tiempo que debe tomar una orden marcada +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Cambia la cantidad de tiempo que debe tardar una orden marcada STR_TIMETABLE_CLEAR_TIME :{BLACK}Limpiar Horario STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Limpiar la cantidad de tiempo para la orden seleccionada @@ -4068,13 +4068,13 @@ STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}El guard STR_ERROR_AUTOSAVE_FAILED :{WHITE}Error en Autoguardado STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}No es posible leer la unidad STR_ERROR_GAME_SAVE_FAILED :{WHITE}Error guardando juego{}{STRING} -STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}No es posible borrar el fichero +STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}No es posible borrar el archivo STR_ERROR_GAME_LOAD_FAILED :{WHITE}Carga de Juego Errónea{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Error interno: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Partida guardada corrupta - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :La partida guardada ha sido realizada con una versión más nueva -STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :No se puede leer fichero -STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :No se puede escribir en el fichero +STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Archivo no legible +STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :No se puede escribir en el archivo STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Comprobación de integridad de los datos fallida STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}El juego ha sido guardado en una versión sin soporte para tranvías. Todos los tranvías serán eliminados @@ -4084,7 +4084,7 @@ STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Generaci STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... no hay municipios en el escenario STR_ERROR_PNGMAP :{WHITE}No se pudo cargar mapa de alturas PNG... -STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... fichero no encontrado +STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... archivo no encontrado STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... no se pudo convertir tipo de imagen. Se requieren imágenes PNG de 8 o 24-bits STR_ERROR_PNGMAP_MISC :{WHITE}... algo ha salido mal (es probable que el fichero esté corrupto) @@ -4604,7 +4604,7 @@ STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Vapor) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Vapor) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) -STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) +STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diésel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 34225d0f9d..d3a4ca9048 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -844,6 +844,7 @@ STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} chưa có lệnh STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} có các lệnh trùng lặp STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} có trạm bất hợp lệ trong lệnh +STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}{VEHICLE} có trong lộ trình một sân bay có đường băng quá ngắn STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} đang cũ đi STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} đang xuống cấp @@ -1287,17 +1288,28 @@ STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Hiển thị d STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Độ đậm của đường kẻ trong đồ thị: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Độ đậm của đường vẽ trên đồ thị. Một đường mảnh sẽ chính xác hơn, trong khi đó đường đậm sẽ dễ nhìn hơn và màu sắc dễ phân biệt hơn +STR_CONFIG_SETTING_LANDSCAPE :Nền đất: {STRING} +STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Nền đất là định nghĩa cơ bản của các màn chơi với các kiểu hàng hóa và yêu cầu cho sự phát triển đô thị khác nhau. NewGRF và kịch bản chơi cho phép các điều chỉnh nhỏ hơn. STR_CONFIG_SETTING_LAND_GENERATOR :Tạo nền đất: {STRING} +STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Bộ khởi tạo nguyên bản chỉ dựa vào tập hợp đồ họa đối tượng cơ bản, rồi sinh ra các dạng địa hình cố đinh. Với TerraGenesis thì dựa trên có chế nhiễu loạn (noise) kiểu Perlin và cho phép các điều chỉnh nhỏ hơn. STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Nguyên Bản STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis +STR_CONFIG_SETTING_TERRAIN_TYPE :Kiểu nền đất: {STRING} +STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Chỉ cho TerraGenesis) Địa hình nhiều đồi núi +STR_CONFIG_SETTING_INDUSTRY_DENSITY :Mật độ nhà máy: {STRING} +STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Thiết lập số nhà máy sẽ được tạo ra và mức độ dùy trì trong ván chơi STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Khoảng cách tối đa từ lề bản đồ tới nhà máy lọc dầu: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Nhà máy hóa dầu chỉ có thể xây gần rìa bản đồ, tương ứng là ven biển với những bản đồ dạng đảo STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Độ cao tuyết phủ: {STRING} +STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Điều chỉnh độ cao của tuyết phủ đối với địa hình xứ lanh. Tuyết phủ có thể ảnh hưởng tới việc tạo ra nhà máy và các yêu cầu cho sự tăng trưởng đô thị STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Độ gồ ghề của địa chất: {STRING} +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Chỉ cho TerraGenesis) Chọn mức độ trùng điệp của núi: địa hình bằng phẳng thì ít hơn, địa hình đồi núi thì nhiều hơn. Địa hình gồ ghề có nhiều núi và trông có vẻ lặp lại STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Rất Phẳng STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Phẳng STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Gồ Ghề STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Rất Gồ Ghề +STR_CONFIG_SETTING_VARIETY :Phân bổ sự đa dạng: {STRING} +STR_CONFIG_SETTING_VARIETY_HELPTEXT :(Chỉ cho TerraGenesis) Điều chỉnh liệu rằng bản đồ gồm cả vùng núi cao và vùng đồng bằng. Đây chỉ là điều chỉnh cho sự bằng phẳng hơn, các thiết lập khác sẽ điều chỉnh cho vùng núi. STR_CONFIG_SETTING_RIVER_AMOUNT :Số lượng sông ngòi: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Chọn số lượng sông ngòi được khởi tạo STR_CONFIG_SETTING_TREE_PLACER :Thuật toán đặt cây: {STRING} @@ -2863,6 +2875,10 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Sprite t STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Xử lý sprite bình thường ở trước, bỏ qua các loại pseudo/recolour/font sprite căn theo điểm bắt đầu STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Theo những thông tin của sprite đã chọn. Thì việc căn chỉnh khi vẽ đối với sprite này sẽ bị bỏ qua STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Di chuyển sprite xung quanh, thay đổi X và Y offsets +STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Đặt lại tương đối +STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Đặt lại các dịch chuyển tương đối hiện tại +STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK} dịch X: {NUM}, dịch Y: {NUM} (tuyệt đối) +STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}toạ độ X: {NUM}, toạ độ Y: {NUM} (tương đối) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Chọn sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Chọn sprite ở bất cứ đâu trên màn hình diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index bc4c18db46..d25dfff6c7 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -284,8 +284,8 @@ STR_SORT_BY_PRODUCTION :Cynyrch STR_SORT_BY_TYPE :Math STR_SORT_BY_TRANSPORTED :Wedi'i gludo STR_SORT_BY_NUMBER :Rhif -STR_SORT_BY_PROFIT_LAST_YEAR :Elw eleni -STR_SORT_BY_PROFIT_THIS_YEAR :Elw llynedd +STR_SORT_BY_PROFIT_LAST_YEAR :Elw llynedd +STR_SORT_BY_PROFIT_THIS_YEAR :Elw eleni STR_SORT_BY_AGE :Oed STR_SORT_BY_RELIABILITY :Dibynadwyedd STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Cyfanswm Gallu Cludo fesul y math o lwyth diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 8cadcda6be..758c927065 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1869,7 +1869,9 @@ struct NetworkClientListWindow : Window { int selected_item; uint server_client_width; - uint company_icon_width; + uint line_height; + + Dimension icon_size; NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), @@ -1891,7 +1893,7 @@ struct NetworkClientListWindow : Window { if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++; } - num *= FONT_HEIGHT_NORMAL; + num *= this->line_height; int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget(WID_CL_PANEL)->current_y); /* If height is changed */ @@ -1907,7 +1909,8 @@ struct NetworkClientListWindow : Window { if (widget != WID_CL_PANEL) return; this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT; - this->company_icon_width = GetSpriteSize(SPR_COMPANY_ICON).width + WD_FRAMERECT_LEFT; + this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); + this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); uint width = 100; // Default width const NetworkClientInfo *ci; @@ -1915,7 +1918,7 @@ struct NetworkClientListWindow : Window { width = max(width, GetStringBoundingBox(ci->client_name).width); } - size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT; + size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT; } virtual void OnPaint() @@ -1931,11 +1934,13 @@ struct NetworkClientListWindow : Window { if (widget != WID_CL_PANEL) return; bool rtl = _current_text_dir == TD_RTL; - int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - 10) / 2; + int icon_offset = (this->line_height - icon_size.height) / 2; + int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + uint y = r.top + WD_FRAMERECT_TOP; uint left = r.left + WD_FRAMERECT_LEFT; uint right = r.right - WD_FRAMERECT_RIGHT; - uint type_icon_width = this->server_client_width + this->company_icon_width; + uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT; uint type_left = rtl ? right - this->server_client_width : left; @@ -1949,24 +1954,24 @@ struct NetworkClientListWindow : Window { FOR_ALL_CLIENT_INFOS(ci) { TextColour colour; if (this->selected_item == i++) { // Selected item, highlight it - GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK); + GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK); colour = TC_WHITE; } else { colour = TC_BLACK; } if (ci->client_id == CLIENT_ID_SERVER) { - DrawString(type_left, type_right, y, STR_NETWORK_SERVER, colour); + DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour); } else { - DrawString(type_left, type_right, y, STR_NETWORK_CLIENT, colour); + DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour); } /* Filter out spectators */ - if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_y_offset); + if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset); - DrawString(name_left, name_right, y, ci->client_name, colour); + DrawString(name_left, name_right, y + text_offset, ci->client_name, colour); - y += FONT_HEIGHT_NORMAL; + y += line_height; } } @@ -1999,7 +2004,7 @@ struct NetworkClientListWindow : Window { pt.y -= this->GetWidget(WID_CL_PANEL)->pos_y; int item = -1; if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) { - item = (pt.y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL; + item = (pt.y - WD_FRAMERECT_TOP) / this->line_height; } /* It did not change.. no update! */ diff --git a/src/order_base.h b/src/order_base.h index 2edcf9145c..24afcf65a3 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -149,6 +149,8 @@ public: inline OrderDepotTypeFlags GetDepotOrderType() const { return (OrderDepotTypeFlags)GB(this->flags, 0, 3); } /** What are we going to do when in the depot. */ inline OrderDepotActionFlags GetDepotActionType() const { return (OrderDepotActionFlags)GB(this->flags, 4, 3); } + /** What waypoint flags? */ + inline OrderWaypointFlags GetWaypointFlags() const { return (OrderWaypointFlags)GB(this->flags, 0, 8); } /** What variable do we have to compare? */ inline OrderConditionVariable GetConditionVariable() const { return (OrderConditionVariable)GB(this->dest, 11, 5); } /** What is the comparator to use? */ @@ -170,6 +172,8 @@ public: inline void SetDepotOrderType(OrderDepotTypeFlags depot_order_type) { SB(this->flags, 0, 3, depot_order_type); } /** Set what we are going to do in the depot. */ inline void SetDepotActionType(OrderDepotActionFlags depot_service_type) { SB(this->flags, 4, 3, depot_service_type); } + /** Set waypoint flags. */ + inline void SetWaypointFlags(OrderWaypointFlags waypoint_flags) { SB(this->flags, 0, 8, waypoint_flags); } /** Set variable we have to compare. */ inline void SetConditionVariable(OrderConditionVariable condition_variable) { SB(this->dest, 11, 5, condition_variable); } /** Set the comparator to use. */ diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 42f3b0f5d0..9279306003 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1377,7 +1377,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 break; case OT_GOTO_WAYPOINT: - if (mof != MOF_NON_STOP) return CMD_ERROR; + if (mof != MOF_NON_STOP && mof != MOF_WAYPOINT_FLAGS) return CMD_ERROR; break; case OT_CONDITIONAL: @@ -1470,6 +1470,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case MOF_COND_DESTINATION: if (data >= v->GetNumOrders()) return CMD_ERROR; break; + + case MOF_WAYPOINT_FLAGS: + if (data != (data & OWF_REVERSE)) return CMD_ERROR; + break; } if (flags & DC_EXEC) { @@ -1571,6 +1575,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 order->SetConditionSkipToOrder(data); break; + case MOF_WAYPOINT_FLAGS: + order->SetWaypointFlags((OrderWaypointFlags)data); + break; + default: NOT_REACHED(); } diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 0fbeff38b3..35eee48048 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -350,10 +350,13 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } break; - case OT_GOTO_WAYPOINT: - SetDParam(0, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT); + case OT_GOTO_WAYPOINT: { + StringID str = (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT; + if (order->GetWaypointFlags() & OWF_REVERSE) str += STR_ORDER_GO_TO_WAYPOINT_REVERSE - STR_ORDER_GO_TO_WAYPOINT; + SetDParam(0, str); SetDParam(1, order->GetDestination()); break; + } case OT_CONDITIONAL: { SetDParam(1, order->GetConditionSkipToOrder() + 1); @@ -554,6 +557,7 @@ private: /* WID_O_SEL_TOP_LEFT */ DP_LEFT_LOAD = 0, ///< Display 'load' in the left button of the top row of the train/rv order window. DP_LEFT_REFIT = 1, ///< Display 'refit' in the left button of the top row of the train/rv order window. + DP_LEFT_REVERSE = 2, ///< Display 'reverse' in the left button of the top row of the train/rv order window. /* WID_O_SEL_TOP_MIDDLE */ DP_MIDDLE_UNLOAD = 0, ///< Display 'unload' in the middle button of the top row of the train/rv order window. @@ -798,11 +802,12 @@ private: /* When networking, move one order lower */ int selected = this->selected_order + (int)_networking; - MarkAllRoutePathsDirty(this->vehicle); MarkAllRouteStepsDirty(this); if (DoCommandP(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER))) { this->selected_order = selected >= this->vehicle->GetNumOrders() ? -1 : selected; this->UpdateButtonState(); + MarkAllRoutePathsDirty(this->vehicle); + MarkAllRouteStepsDirty(this); } } @@ -1125,13 +1130,14 @@ public: row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); - left_sel->SetDisplayedPlane(DP_LEFT_LOAD); + left_sel->SetDisplayedPlane(DP_LEFT_REVERSE); middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD); right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY); this->EnableWidget(WID_O_NON_STOP); this->SetWidgetLoweredState(WID_O_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); + this->EnableWidget(WID_O_REVERSE); + this->SetWidgetLoweredState(WID_O_REVERSE, order->GetWaypointFlags() & OWF_REVERSE); } - this->DisableWidget(WID_O_FULL_LOAD); this->DisableWidget(WID_O_UNLOAD); this->DisableWidget(WID_O_REFIT_DROPDOWN); break; @@ -1461,6 +1467,17 @@ public: } break; + case WID_O_REVERSE: { + VehicleOrderID sel_ord = this->OrderGetSel(); + const Order *order = this->vehicle->GetOrder(sel_ord); + + if (order == NULL) break; + + DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_WAYPOINT_FLAGS | (order->GetWaypointFlags() ^ OWF_REVERSE) << 4, + CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); + break; + } + case WID_O_COND_CARGO: { uint value = this->vehicle->GetOrder(this->OrderGetSel())->GetConditionValue(); ShowDropDownMenu(this, cargo_names_list, value, WID_O_COND_CARGO, 0, cargo_bitmask); @@ -1775,6 +1792,8 @@ static const NWidgetPart _nested_orders_train_widgets[] = { SetDataTip(STR_ORDER_TOGGLE_FULL_LOAD, STR_ORDER_TOOLTIP_FULL_LOAD), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_REFIT), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_REVERSE), SetMinimalSize(93, 12), SetFill(1, 0), + SetDataTip(STR_ORDER_REVERSE, STR_ORDER_REVERSE_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_MIDDLE), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_UNLOAD), SetMinimalSize(93, 12), SetFill(1, 0), @@ -1947,6 +1966,12 @@ void ShowOrdersWindow(const Vehicle *v) DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); if (BringWindowToFrontById(WC_VEHICLE_ORDERS, v->index) != NULL) return; + /* Using a different WindowDescs for _local_company causes problems. + * Due to this we have to close order windows in ChangeWindowOwner/DeleteCompanyWindows, + * because we cannot change switch the WindowDescs and keeping the old WindowDesc results + * in crashed due to missing widges. + * TODO Rewrite the order GUI to not use different WindowDescs. + */ if (v->owner != _local_company) { new OrdersWindow(&_other_orders_desc, v); } else { diff --git a/src/order_type.h b/src/order_type.h index 646d38147e..b390a3a1a1 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -114,6 +114,15 @@ enum OrderDepotActionFlags { }; DECLARE_ENUM_AS_BIT_SET(OrderDepotActionFlags) +/** + * Flags for go to waypoint orders + */ +enum OrderWaypointFlags { + OWF_DEFAULT = 0, ///< Default waypoint behaviour + OWF_REVERSE = 1 << 0, ///< Reverse train at the waypoint +}; +DECLARE_ENUM_AS_BIT_SET(OrderWaypointFlags) + /** * Variables (of a vehicle) to 'cause' skipping on. */ @@ -161,6 +170,7 @@ enum ModifyOrderFlags { MOF_COND_COMPARATOR, ///< A comparator changes. MOF_COND_VALUE, ///< The value to set the condition to. MOF_COND_DESTINATION,///< Change the destination of a conditional order. + MOF_WAYPOINT_FLAGS, ///< Change the waypoint flags MOF_END }; template <> struct EnumPropsT : MakeEnumPropsT {}; diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index 5d3b5b0778..6cdf4c7e43 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -145,7 +145,12 @@ struct CFollowTrackT * missing road bit, or inability to connect the * different bits due to slopes. */ if (IsRoadTT() && !IsTram() && TryReverse()) return true; + + /* CanEnterNewTile already set a reason. + * Do NOT overwrite it (important for example for EC_RAIL_TYPE). + * Only set a reason if CanEnterNewTile was not called */ if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY; + return false; } if (!Allow90degTurns()) { diff --git a/src/rail.h b/src/rail.h index 539a162b8e..320d24a9a0 100644 --- a/src/rail.h +++ b/src/rail.h @@ -431,4 +431,13 @@ void ResetRailTypes(); void InitRailTypes(); RailType AllocateRailType(RailTypeLabel label); +extern RailType _sorted_railtypes[RAILTYPE_END]; +extern uint8 _sorted_railtypes_size; + +/** + * Loop header for iterating over railtypes, sorted by sortorder. + * @param var Railtype. + */ +#define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes_size && (var = _sorted_railtypes[index], true) ; index++) + #endif /* RAIL_H */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 5b18e4b4e7..f6e514d1e8 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -46,6 +46,8 @@ typedef SmallVector TrainList; RailtypeInfo _railtypes[RAILTYPE_END]; +RailType _sorted_railtypes[RAILTYPE_END]; +uint8 _sorted_railtypes_size; assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes)); @@ -113,6 +115,17 @@ void ResolveRailTypeGUISprites(RailtypeInfo *rti) } } +/** + * Compare railtypes based on their sorting order. + * @param first The railtype to compare to. + * @param second The railtype to compare. + * @return True iff the first should be sorted before the second. + */ +static int CDECL CompareRailTypes(const RailType *first, const RailType *second) +{ + return GetRailTypeInfo(*first)->sorting_order - GetRailTypeInfo(*second)->sorting_order; +} + /** * Resolve sprites of custom rail types */ @@ -122,6 +135,14 @@ void InitRailTypes() RailtypeInfo *rti = &_railtypes[rt]; ResolveRailTypeGUISprites(rti); } + + _sorted_railtypes_size = 0; + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + if (_railtypes[rt].label != 0) { + _sorted_railtypes[_sorted_railtypes_size++] = rt; + } + } + QSortT(_sorted_railtypes, _sorted_railtypes_size, CompareRailTypes); } /** @@ -1041,7 +1062,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, } if (flags & DC_EXEC) { if (p2 == 0 && HasWormholeSignals(tile)) { // Toggle signal if already signals present. - if (IsTunnelBridgeEntrance (tile)) { + if (IsTunnelBridgeEntrance(tile)) { ClrBitTunnelBridgeSignal(tile); ClrBitTunnelBridgeExit(tile_exit); SetBitTunnelBridgeExit(tile); @@ -1052,7 +1073,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, SetBitTunnelBridgeExit(tile_exit); SetBitTunnelBridgeSignal(tile); } - } else{ + } else { /* Create one direction tunnel/bridge if required. */ if (p2 == 0) { SetBitTunnelBridgeSignal(tile); @@ -1072,7 +1093,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, } MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile_exit); - AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company); + AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile)); YapfNotifyTrackLayoutChange(tile, track); } return cost; @@ -1526,6 +1547,8 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 _m[end].m2 = 0; MarkTileDirtyByTile(tile); MarkTileDirtyByTile(end); + AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile)); + YapfNotifyTrackLayoutChange(tile, track); return CommandCost(EXPENSES_CONSTRUCTION, cost); } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 64a985a441..9f337ed276 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -2052,17 +2052,6 @@ void InitializeRailGUI() ResetSignalVariant(); } -/** - * Compare railtypes based on their sorting order. - * @param first The railtype to compare to. - * @param second The railtype to compare. - * @return True iff the first should be sorted before the second. - */ -static int CDECL CompareRailTypes(const DropDownListItem * const *first, const DropDownListItem * const *second) -{ - return GetRailTypeInfo((RailType)(*first)->result)->sorting_order - GetRailTypeInfo((RailType)(*second)->result)->sorting_order; -} - /** * Create a drop down list for all the rail types of the local company. * @param for_replacement Whether this list is for the replacement window. @@ -2085,13 +2074,12 @@ DropDownList *GetRailTypeDropDownList(bool for_replacement) const Company *c = Company::Get(_local_company); DropDownList *list = new DropDownList(); - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { /* If it's not used ever, don't show it to the user. */ if (!HasBit(used_railtypes, rt)) continue; const RailtypeInfo *rti = GetRailTypeInfo(rt); - /* Skip rail type if it has no label */ - if (rti->label == 0) continue; StringID str = for_replacement ? rti->strings.replace_text : (rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING); DropDownListParamStringItem *item = new DropDownListParamStringItem(str, rt, !HasBit(c->avail_railtypes, rt)); @@ -2099,6 +2087,5 @@ DropDownList *GetRailTypeDropDownList(bool for_replacement) item->SetParam(1, rti->max_speed); *list->Append() = item; } - QSortT(list->Begin(), list->Length(), CompareRailTypes); return list; } diff --git a/src/road.cpp b/src/road.cpp index 57c5da5d41..f51597538d 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -57,41 +57,44 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) bool connective = false; const RoadBits mirrored_rb = MirrorRoadBits(target_rb); - switch (GetTileType(neighbor_tile)) { - /* Always connective ones */ - case MP_CLEAR: case MP_TREES: - connective = true; - break; + if (IsValidTile(neighbor_tile)) { + switch (GetTileType(neighbor_tile)) { + /* Always connective ones */ + case MP_CLEAR: case MP_TREES: + connective = true; + break; - /* The conditionally connective ones */ - case MP_TUNNELBRIDGE: - case MP_STATION: - case MP_ROAD: { - const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, ROADTYPE_TRAM); + /* The conditionally connective ones */ + case MP_TUNNELBRIDGE: + case MP_STATION: + case MP_ROAD: + if (IsNormalRoadTile(neighbor_tile)) { + /* Always connective */ + connective = true; + } else { + const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, ROADTYPE_TRAM); - /* Accept only connective tiles */ - connective = (neighbor_rb & mirrored_rb) || // Neighbor has got the fitting RoadBit - HasExactlyOneBit(neighbor_rb); // Neighbor has got only one Roadbit + /* Accept only connective tiles */ + connective = (neighbor_rb & mirrored_rb) != ROAD_NONE; + } + break; - break; + case MP_RAILWAY: + connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir)); + break; + + case MP_WATER: + /* Check for real water tile */ + connective = !IsWater(neighbor_tile); + break; + + /* The definitely not connective ones */ + default: break; } - - case MP_RAILWAY: - connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir)); - break; - - case MP_WATER: - /* Check for real water tile */ - connective = !IsWater(neighbor_tile); - break; - - /* The definitely not connective ones */ - default: break; } /* If the neighbor tile is inconnective, remove the planed road connection to it */ if (!connective) org_rb ^= target_rb; - } } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 7052c4730a..02686bc1ae 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3074,6 +3074,13 @@ bool AfterLoadGame() } } + if (SlXvIsFeatureMissing(XSLFI_REVERSE_AT_WAYPOINT)) { + Train *t; + FOR_ALL_TRAINS(t) { + t->reverse_distance = 0; + } + } + /* * Only keep order-backups for network clients (and when replaying). * If we are a network server or not networking, then we just loaded a previously @@ -3182,6 +3189,14 @@ bool AfterLoadGame() FOR_ALL_STATIONS(st) UpdateStationAcceptance(st, false); } + // setting moved from game settings to company settings + if (SlXvIsFeaturePresent(XSLFI_ORDER_OCCUPANCY, 1, 1)) { + Company *c; + FOR_ALL_COMPANIES(c) { + c->settings.order_occupancy_smoothness = _settings_game.order.old_occupancy_smoothness; + } + } + /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 51be3e1882..64926ecad0 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -16,6 +16,7 @@ #include "../tunnelbridge_map.h" #include "../tunnelbridge.h" #include "../station_base.h" +#include "../settings_func.h" #include "saveload.h" @@ -312,7 +313,7 @@ static const SaveLoad _company_settings_desc[] = { SLE_CONDVAR(Company, settings.vehicle.servint_roadveh, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_aircraft, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_ships, SLE_UINT16, 120, SL_MAX_VERSION), - SLE_CONDVAR_X(Company, settings.vehicle.auto_timetable_by_default, SLE_BOOL, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2)), + SLE_CONDVAR_X(Company, settings.vehicle.auto_timetable_by_default, SLE_BOOL, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), SLE_CONDNULL(63, 2, 143), // old reserved space @@ -335,7 +336,7 @@ static const SaveLoad _company_settings_skip_desc[] = { SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_roadveh SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_aircraft SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_ships - SLE_CONDNULL_X(1, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2)), // settings.vehicle.auto_timetable_by_default + SLE_CONDNULL_X(1, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), // settings.vehicle.auto_timetable_by_default SLE_CONDNULL(63, 2, 143), // old reserved space @@ -489,8 +490,14 @@ static void Load_PLYR() int index; while ((index = SlIterateArray()) != -1) { Company *c = new (index) Company(); + SetDefaultCompanySettings(c->index); SaveLoad_PLYR(c); _company_colours[index] = (Colours)c->colour; + + // setting moved from game settings to company settings + if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 2)) { + c->settings.auto_timetable_separation_rate = _settings_game.order.old_timetable_separation_rate; + } } } @@ -532,7 +539,25 @@ static void Ptrs_PLYR() } } +extern void LoadSettingsPlyx(bool skip); +extern void SaveSettingsPlyx(); + +static void Load_PLYX() +{ + LoadSettingsPlyx(false); +} + +static void Check_PLYX() +{ + LoadSettingsPlyx(true); +} + +static void Save_PLYX() +{ + SaveSettingsPlyx(); +} extern const ChunkHandler _company_chunk_handlers[] = { - { 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY | CH_LAST}, + { 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY }, + { 'PLYX', Save_PLYX, Load_PLYX, NULL, Check_PLYX, CH_RIFF | CH_LAST}, }; diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 40aa560ce0..241f56975f 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -56,14 +56,15 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 1, 1, "signal_tunnel_bridge", NULL, NULL, NULL }, { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 1, 1, "improved_breakdowns", NULL, NULL, NULL }, { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL }, - { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 2, 2, "auto_timetables", NULL, NULL, NULL }, + { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 3, 3, "auto_timetables", NULL, NULL, NULL }, { XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 1, 1, "vehicle_repair_cost", NULL, NULL, NULL }, { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 1, 1, "enh_viewport_plans", NULL, NULL, "PLAN,PLLN" }, { XSLFI_INFRA_SHARING, XSCF_NULL, 1, 1, "infra_sharing", NULL, NULL, NULL }, { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 1, 1, "variable_day_length", NULL, NULL, NULL }, - { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 1, 1, "order_occupancy", NULL, NULL, NULL }, + { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", NULL, NULL, NULL }, { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 1, 1, "more_cond_orders", NULL, NULL, NULL }, { XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", NULL, NULL, NULL }, + { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", NULL, NULL, NULL }, { XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 86469e4a29..d99cf702b2 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -45,6 +45,7 @@ enum SlXvFeatureIndex { XSLFI_RAIL_AGEING, ///< This save game uses the rail aging patch XSLFI_SPRINGPP, ///< This is a SpringPP game, use this for loading some settings XSLFI_EXTRA_LARGE_MAP, ///< Extra large map + XSLFI_REVERSE_AT_WAYPOINT, ///< Reverse at waypoint orders XSLFI_SIZE, ///< Total count of features, including null feature }; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2936e3911e..e5e24a8f86 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -570,7 +570,7 @@ void NORETURN SlError(StringID string, const char *extra_msg, bool already_mallo /** * As SlError, except that it takes a format string and additional parameters */ -void CDECL NORETURN SlErrorFmt(StringID string, const char *msg, ...) +void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) { va_list va; va_start(va, msg); @@ -594,7 +594,7 @@ void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced) /** * As SlErrorCorruptFmt, except that it takes a format string and additional parameters */ -void CDECL NORETURN SlErrorCorruptFmt(const char *msg, ...) +void NORETURN CDECL SlErrorCorruptFmt(const char *msg, ...) { va_list va; va_start(va, msg); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 330cdde072..8df011958b 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -631,8 +631,8 @@ void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); void NORETURN SlError(StringID string, const char *extra_msg = NULL, bool already_malloced = false); void NORETURN SlErrorCorrupt(const char *msg, bool already_malloced = false); -void CDECL NORETURN SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); -void CDECL NORETURN SlErrorCorruptFmt(const char *msg, ...) WARN_FORMAT(1, 2); +void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); +void NORETURN CDECL SlErrorCorruptFmt(const char *msg, ...) WARN_FORMAT(1, 2); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 7ca0ec76ad..7b073f4e37 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -759,6 +759,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDNULL(2, 2, 19), SLE_CONDVAR(Train, gv_flags, SLE_UINT16, 139, SL_MAX_VERSION), SLE_CONDNULL(11, 2, 143), // old reserved space + SLE_CONDVAR_X(Train, reverse_distance, SLE_UINT16, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REVERSE_AT_WAYPOINT)), SLE_END() }; diff --git a/src/settings.cpp b/src/settings.cpp index 3b49a45649..d9fd8e6981 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2299,10 +2299,10 @@ static void SaveSettings(const SettingDesc *sd, void *object) * * The PATX chunk contents has the following format: * - * uint32 chunk flags + * uint32 chunk flags (unused) * uint32 number of settings * For each of N settings: - * uint32 setting flags + * uint32 setting flags (unused) * SLE_STR setting name * uint32 length of setting field * N bytes setting field @@ -2333,6 +2333,7 @@ static void MakeSettingsPatxList(const SettingDesc *sd) static const SettingDesc *previous = NULL; if (sd == previous) return; + previous = sd; _sorted_patx_settings.clear(); for (const SettingDesc *desc = sd; desc->save.cmd != SL_END; desc++) { @@ -2343,16 +2344,6 @@ static void MakeSettingsPatxList(const SettingDesc *sd) std::sort(_sorted_patx_settings.begin(), _sorted_patx_settings.end(), StringSorter()); } -/** - * Internal structure used in LoadSettingsPatx() - * placed outside for legacy compiler compatibility - */ -struct SettingsPatxLoad { - uint32 flags; - char name[256]; - uint32 setting_length; -}; - /** * Internal structure used in LoadSettingsPatx() * placed outside for legacy compiler compatibility @@ -2372,6 +2363,38 @@ struct StringSearcher { } }; +/** + * Internal structure used in LoadSettingsPatx() and LoadSettingsPlyx() + */ +struct SettingsExtLoad { + uint32 flags; + char name[256]; + uint32 setting_length; +}; + +static const SaveLoad _settings_ext_load_desc[] = { + SLE_VAR(SettingsExtLoad, flags, SLE_UINT32), + SLE_STR(SettingsExtLoad, name, SLE_STRB, 256), + SLE_VAR(SettingsExtLoad, setting_length, SLE_UINT32), + SLE_END() +}; + +/** + * Internal structure used in SaveSettingsPatx() and SaveSettingsPlyx() + */ +struct SettingsExtSave { + uint32 flags; + const char *name; + uint32 setting_length; +}; + +static const SaveLoad _settings_ext_save_desc[] = { + SLE_VAR(SettingsExtSave, flags, SLE_UINT32), + SLE_STR(SettingsExtSave, name, SLE_STR, 0), + SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32), + SLE_END() +}; + /** * Load handler for settings which go in the PATX chunk * @param osd SettingDesc struct containing all information @@ -2382,14 +2405,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object) { MakeSettingsPatxList(sd); - SettingsPatxLoad current_setting; - - static const SaveLoad _settings_patx_desc[] = { - SLE_VAR(SettingsPatxLoad, flags, SLE_UINT32), - SLE_STR(SettingsPatxLoad, name, SLE_STRB, 256), - SLE_VAR(SettingsPatxLoad, setting_length, SLE_UINT32), - SLE_END() - }; + SettingsExtLoad current_setting; uint32 flags = SlReadUint32(); // flags are not in use yet, reserve for future expansion @@ -2397,7 +2413,7 @@ static void LoadSettingsPatx(const SettingDesc *sd, void *object) uint32 settings_count = SlReadUint32(); for (uint32 i = 0; i < settings_count; i++) { - SlObject(¤t_setting, _settings_patx_desc); + SlObject(¤t_setting, _settings_ext_load_desc); // flags are not in use yet, reserve for future expansion if (current_setting.flags != 0) SlErrorCorruptFmt("PATX chunk: unknown setting header flags: 0x%X", current_setting.flags); @@ -2441,19 +2457,7 @@ struct SettingToAdd { */ static void SaveSettingsPatx(const SettingDesc *sd, void *object) { - struct SettingsPatxSave { - uint32 flags; - const char *name; - uint32 setting_length; - }; - SettingsPatxSave current_setting; - - static const SaveLoad _settings_patx_desc[] = { - SLE_VAR(SettingsPatxSave, flags, SLE_UINT32), - SLE_STR(SettingsPatxSave, name, SLE_STR, 0), - SLE_VAR(SettingsPatxSave, setting_length, SLE_UINT32), - SLE_END() - }; + SettingsExtSave current_setting; std::vector settings_to_add; @@ -2466,7 +2470,7 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object) current_setting.name = desc->patx_name; // add length of setting header - length += SlCalcObjLength(¤t_setting, _settings_patx_desc); + length += SlCalcObjLength(¤t_setting, _settings_ext_save_desc); // add length of actual setting length += setting_length; @@ -2485,12 +2489,171 @@ static void SaveSettingsPatx(const SettingDesc *sd, void *object) current_setting.flags = 0; current_setting.name = desc->patx_name; current_setting.setting_length = settings_to_add[i].setting_length; - SlObject(¤t_setting, _settings_patx_desc); + SlObject(¤t_setting, _settings_ext_save_desc); void *ptr = GetVariableAddress(object, &desc->save); SlObjectMember(ptr, &desc->save); } } +/** @file + * + * The PLYX chunk stores additional company settings in an unordered + * format which is tolerant of extra, missing or reordered settings. + * The format is similar to the PATX chunk. + * Additional settings generally means those that aren't in trunk. + * + * The PLYX chunk contents has the following format: + * + * uint32 chunk flags (unused) + * uint32 number of companies + * For each of N companies: + * uint32 company ID + * uint32 company flags (unused) + * uint32 number of settings + * For each of N settings: + * uint32 setting flags (unused) + * SLE_STR setting name + * uint32 length of setting field + * N bytes setting field + */ + +/** + * Load handler for company settings which go in the PLYX chunk + * @param check_mode Whether to skip over settings without reading + */ +void LoadSettingsPlyx(bool skip) +{ + SettingsExtLoad current_setting; + + uint32 chunk_flags = SlReadUint32(); + // flags are not in use yet, reserve for future expansion + if (chunk_flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown chunk header flags: 0x%X", chunk_flags); + + uint32 company_count = SlReadUint32(); + for (uint32 i = 0; i < company_count; i++) { + uint32 company_id = SlReadUint32(); + if (company_id >= MAX_COMPANIES) SlErrorCorruptFmt("PLYX chunk: invalid company ID: %u", company_id); + + const Company *c = NULL; + if (!skip) { + c = Company::GetIfValid(company_id); + if (c == NULL) SlErrorCorruptFmt("PLYX chunk: non-existant company ID: %u", company_id); + } + + uint32 company_flags = SlReadUint32(); + // flags are not in use yet, reserve for future expansion + if (company_flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown company flags: 0x%X", company_flags); + + uint32 settings_count = SlReadUint32(); + for (uint32 j = 0; j < settings_count; j++) { + SlObject(¤t_setting, _settings_ext_load_desc); + + // flags are not in use yet, reserve for future expansion + if (current_setting.flags != 0) SlErrorCorruptFmt("PLYX chunk: unknown setting header flags: 0x%X", current_setting.flags); + + if (skip) { + SlSkipBytes(current_setting.setting_length); + continue; + } + + const SettingDesc *setting = NULL; + + // not many company settings, so perform a linear scan + for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { + if (desc->patx_name != NULL && strcmp(desc->patx_name, current_setting.name) == 0) { + setting = desc; + break; + } + } + + if (setting != NULL) { + // found setting + const SaveLoad *sld = &(setting->save); + size_t read = SlGetBytesRead(); + void *ptr = GetVariableAddress(&(c->settings), sld); + SlObjectMember(ptr, sld); + if (SlGetBytesRead() != read + current_setting.setting_length) { + SlErrorCorruptFmt("PLYX chunk: setting read length mismatch for setting: '%s'", current_setting.name); + } + if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, setting, ReadValue(ptr, sld->conv)); + } else { + DEBUG(sl, 1, "PLYX chunk: Could not find company setting: '%s', ignoring", current_setting.name); + SlSkipBytes(current_setting.setting_length); + } + } + } +} + +/** + * Save handler for settings which go in the PLYX chunk + */ +void SaveSettingsPlyx() +{ + SettingsExtSave current_setting; + + static const SaveLoad _settings_plyx_desc[] = { + SLE_VAR(SettingsExtSave, flags, SLE_UINT32), + SLE_STR(SettingsExtSave, name, SLE_STR, 0), + SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32), + SLE_END() + }; + + std::vector company_setting_counts; + + size_t length = 8; + uint32 companies_count = 0; + + Company *c; + FOR_ALL_COMPANIES(c) { + length += 12; + companies_count++; + uint32 setting_count = 0; + for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { + if (desc->patx_name == NULL) continue; + uint32 setting_length = SlCalcObjMemberLength(&(c->settings), &desc->save); + if (!setting_length) continue; + + current_setting.name = desc->patx_name; + + // add length of setting header + length += SlCalcObjLength(¤t_setting, _settings_ext_save_desc); + + // add length of actual setting + length += setting_length; + + setting_count++; + } + company_setting_counts.push_back(setting_count); + } + SlSetLength(length); + + SlWriteUint32(0); // flags + SlWriteUint32(companies_count); // companies count + + size_t index = 0; + FOR_ALL_COMPANIES(c) { + length += 12; + companies_count++; + SlWriteUint32(c->index); // company ID + SlWriteUint32(0); // flags + SlWriteUint32(company_setting_counts[index]); // setting count + index++; + + for (const SettingDesc *desc = _company_settings; desc->save.cmd != SL_END; desc++) { + if (desc->patx_name == NULL) continue; + uint32 setting_length = SlCalcObjMemberLength(&(c->settings), &desc->save); + if (!setting_length) continue; + + current_setting.flags = 0; + current_setting.name = desc->patx_name; + current_setting.setting_length = setting_length; + SlObject(¤t_setting, _settings_plyx_desc); + void *ptr = GetVariableAddress(&(c->settings), &desc->save); + SlObjectMember(ptr, &desc->save); + } + } +} + static void Load_OPTS() { /* Copy over default setting since some might not get loaded in diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 5b9fcb9544..436eab9491 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1635,6 +1635,8 @@ static SettingsContainer &GetSettingsTree() company->Add(new SettingEntry("vehicle.servint_ships")); company->Add(new SettingEntry("vehicle.servint_aircraft")); company->Add(new SettingEntry("vehicle.auto_timetable_by_default")); + company->Add(new SettingEntry("auto_timetable_separation_rate")); + company->Add(new SettingEntry("order_occupancy_smoothness")); } SettingsPage *accounting = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCOUNTING)); @@ -1678,9 +1680,7 @@ static SettingsContainer &GetSettingsTree() vehicles->Add(new SettingEntry("order.serviceathelipad")); vehicles->Add(new SettingEntry("order.timetable_automated")); vehicles->Add(new SettingEntry("order.timetable_separation")); - vehicles->Add(new SettingEntry("order.timetable_separation_rate")); vehicles->Add(new SettingEntry("vehicle.adjacent_crossings")); - vehicles->Add(new SettingEntry("order.occupancy_smoothness")); } SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS)); diff --git a/src/settings_type.h b/src/settings_type.h index 403a475db0..b4d81f0e70 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -479,9 +479,10 @@ struct OrderSettings { bool no_servicing_if_no_breakdowns; ///< don't send vehicles to depot when breakdowns are disabled bool timetable_automated; ///< whether to automatically manage timetables bool timetable_separation; ///< whether to perform automatic separation based on timetable - uint8 timetable_separation_rate; ///< percentage of timetable separation change to apply bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot) - uint8 occupancy_smoothness; ///< percentage smoothness of occupancy measurement changes + + uint8 old_occupancy_smoothness; ///< moved to company settings: percentage smoothness of occupancy measurement changes + uint8 old_timetable_separation_rate; ///< moved to company settings: percentage of timetable separation change to apply }; /** Settings related to vehicles. */ @@ -588,6 +589,8 @@ struct CompanySettings { uint32 engine_renew_money; ///< minimum amount of money before autorenew is used bool renew_keep_length; ///< sell some wagons if after autoreplace the train is longer than before VehicleDefaultSettings vehicle; ///< default settings for vehicles + uint8 order_occupancy_smoothness; ///< percentage smoothness of occupancy measurement changes + uint8 auto_timetable_separation_rate; ///< percentage of auto timetable separation change to apply }; /** All settings together for the game. */ diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 720ee0d281..70e535e20a 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3244,6 +3244,11 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i { if (v->type == VEH_TRAIN) { StationID station_id = GetStationIndex(tile); + if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->current_order.GetDestination() == station_id && v->current_order.GetWaypointFlags() & OWF_REVERSE) { + Train *t = Train::From(v); + // reverse at waypoint + if (t->reverse_distance == 0) t->reverse_distance = t->gcache.cached_total_length; + } if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE; if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE; diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index ae56995561..e662cb25b5 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -18,8 +18,8 @@ static const SettingDesc _company_settings[] = { [post-amble] }; [templates] -SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, NULL), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, NULL), +SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, $patxname), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extver, $patxname), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_END = SDT_END() @@ -36,6 +36,7 @@ from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED extver = SlXvFeatureTest() +patxname = NULL @@ -147,6 +148,37 @@ guiflags = SGF_PER_COMPANY def = false str = STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT strhelp = STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT_HELPTEXT +patxname = ""vehicle.auto_timetable_by_default"" + +[SDT_VAR] +base = CompanySettings +var = auto_timetable_separation_rate +type = SLE_UINT8 +guiflags = SGF_PER_COMPANY +def = 40 +min = 0 +max = 100 +interval = 10 +str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE +strhelp = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE_HELPTEXT +strval = STR_CONFIG_SETTING_PERCENTAGE +cat = SC_EXPERT +patxname = ""auto_timetable_separation_rate"" + +[SDT_VAR] +base = CompanySettings +var = order_occupancy_smoothness +type = SLE_UINT8 +guiflags = SGF_PER_COMPANY +def = 75 +min = 0 +max = 100 +interval = 10 +str = STR_CONFIG_OCCUPANCY_SMOOTHNESS +strhelp = STR_CONFIG_OCCUPANCY_SMOOTHNESS_HELPTEXT +strval = STR_CONFIG_SETTING_PERCENTAGE +cat = SC_EXPERT +patxname = ""order_occupancy_smoothness"" [SDT_END] diff --git a/src/table/settings.ini b/src/table/settings.ini index 475329b710..86e67babb1 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -367,7 +367,7 @@ patxname = ""auto_timetables.order.timetable_separation"" [SDT_VAR] base = GameSettings -var = order.timetable_separation_rate +var = order.old_timetable_separation_rate type = SLE_UINT8 def = 100 min = 0 @@ -377,7 +377,7 @@ str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE strhelp = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE cat = SC_EXPERT -extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE) +extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 1, 2) patxname = ""auto_timetables.order.timetable_separation_rate"" ; There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow @@ -2537,7 +2537,7 @@ cat = SC_EXPERT [SDT_VAR] base = GameSettings -var = order.occupancy_smoothness +var = order.old_occupancy_smoothness type = SLE_UINT8 def = 75 min = 0 @@ -2547,7 +2547,7 @@ str = STR_CONFIG_OCCUPANCY_SMOOTHNESS strhelp = STR_CONFIG_OCCUPANCY_SMOOTHNESS_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE cat = SC_EXPERT -extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_OCCUPANCY) +extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_OCCUPANCY, 1, 1) patxname = ""order_occupancy.order.occupancy_smoothness"" ## diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index c2d800e28d..4524fb74ba 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -17,6 +17,7 @@ #include "vehicle_base.h" #include "settings_type.h" #include "cmd_helper.h" +#include "company_base.h" #include "core/sort_func.hpp" #include "settings_type.h" @@ -322,7 +323,11 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, w->lateness_counter = 0; ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED); /* Do multiplication, then division to reduce rounding errors. */ +#if WALLCLOCK_NETWORK_COMPATIBLE w->timetable_start = start_date + idx * total_duration / num_vehs / DAY_TICKS; +#else + w->timetable_start = start_date + idx * total_duration / num_vehs; +#endif SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index); } @@ -558,9 +563,11 @@ void UpdateSeparationOrder(Vehicle *v_start) int separation_ahead = SeparationBetween(v, v->AheadSeparation()); int separation_behind = SeparationBetween(v->BehindSeparation(), v); if (separation_ahead != -1 && separation_behind != -1) { + Company *owner = Company::GetIfValid(v->owner); + uint8 timetable_separation_rate = owner ? owner->settings.auto_timetable_separation_rate : 100; int new_lateness = (separation_ahead - separation_behind) / 2; - v->lateness_counter = (new_lateness * _settings_game.order.timetable_separation_rate + - v->lateness_counter * (100 - _settings_game.order.timetable_separation_rate)) / 100; + v->lateness_counter = (new_lateness * timetable_separation_rate + + v->lateness_counter * (100 - timetable_separation_rate)) / 100; } v = v->AheadSeparation(); } while (v != v_start); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 50ccd493fa..b3cb198572 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -1395,8 +1395,8 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t /* FALL THROUGH */ case TL_2X2_GRID: - rcmd = GetTownRoadGridElement(t1, house_tile, target_dir); - allow_house = (rcmd == ROAD_NONE); + rcmd = GetTownRoadGridElement(t1, tile, target_dir); + allow_house = (rcmd & DiagDirToRoadBits(target_dir)) == ROAD_NONE; break; case TL_BETTER_ROADS: // Use original afterwards! @@ -1526,13 +1526,12 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) /* Try to grow the town from this point */ GrowTownInTile(&tile, cur_rb, target_dir, t); + if (_grow_town_result == GROWTH_SUCCEED) return true; /* Exclude the source position from the bitmask * and return if no more road blocks available */ if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir)); - if (cur_rb == ROAD_NONE) { - return _grow_town_result == GROWTH_SUCCEED; - } + if (cur_rb == ROAD_NONE) return false; if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Only build in the direction away from the tunnel or bridge. */ @@ -1567,7 +1566,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) /* Max number of times is checked. */ } while (--_grow_town_result >= 0); - return _grow_town_result == GROWTH_SUCCEED - 1; + return false; } /** diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 2164777511..ac2d993e74 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1420,7 +1420,7 @@ public: if (_cur_house != INVALID_HOUSE_ID) matrix->SetClicked(this->house_offset); // set clicked item again to make it visible } - virtual void OnInit() override + virtual void OnInit() OVERRIDE { this->house_list.Build(); this->RestoreSelectedHouseIndex(); @@ -1690,12 +1690,12 @@ public: } } - virtual void OnPlaceObject(Point pt, TileIndex tile) override + virtual void OnPlaceObject(Point pt, TileIndex tile) OVERRIDE { PlaceProc_House(tile); } - virtual void OnPlaceObjectAbort() override + virtual void OnPlaceObjectAbort() OVERRIDE { this->house_offset = -1; _cur_house = INVALID_HOUSE_ID; diff --git a/src/train.h b/src/train.h index d615b40933..50500e21d5 100644 --- a/src/train.h +++ b/src/train.h @@ -113,6 +113,8 @@ struct Train FINAL : public GroundVehicle { /** Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through signals. */ uint16 wait_counter; + uint16 reverse_distance; + /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Train() : GroundVehicleBase() {} /** We want to 'destruct' the right class. */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2cba5c951f..2fd0b22f5f 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -671,6 +671,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const v->owner = _current_company; v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_DEFPAL; + v->reverse_distance = 0; v->SetWagon(); @@ -805,6 +806,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->refit_cap = 0; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; + v->reverse_distance = 0; v->engine_type = e->index; v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback @@ -1437,13 +1439,15 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3 return ret; } - CommandCost cost(EXPENSES_NEW_VEHICLES); - for (Train *t = sell_head; t != NULL; t = t->Next()) cost.AddCost(-t->value); - if (first->orders.list == NULL && !OrderList::CanAllocateItem()) { + /* Restore the train we had. */ + RestoreTrainBackup(original); return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } + CommandCost cost(EXPENSES_NEW_VEHICLES); + for (Train *t = sell_head; t != NULL; t = t->Next()) cost.AddCost(-t->value); + /* do it? */ if (flags & DC_EXEC) { /* First normalise the sub types of the chain. */ @@ -1902,6 +1906,8 @@ void ReverseTrainDirection(Train *v) InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); } + v->reverse_distance = 0; + /* Clear path reservation in front if train is not stuck. */ if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v); @@ -3320,6 +3326,7 @@ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) } SigSegState seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); if (seg_state == SIGSEG_FULL || (seg_state == SIGSEG_PBS && !TryPathReserve(t))) { + t->vehstatus |= VS_TRAIN_SLOWING; t->cur_speed = 0; return true; } @@ -3350,6 +3357,17 @@ static void HandleSignalBehindTrain(Train *v, uint signal_number) } } +uint16 ReversingDistanceTargetSpeed(const Train *v) +{ + int target_speed; + if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC) { + target_speed = ((v->reverse_distance - 1) * 5) / 2; + } else { + target_speed = (v->reverse_distance - 1) * 10 - 5; + } + return max(0, target_speed); +} + /** * Move a vehicle chain one movement stop forwards. * @param v First vehicle to move. @@ -3363,6 +3381,15 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) Train *prev; bool direction_changed = false; // has direction of any part changed? + if (reverse && v->reverse_distance == 1) { + goto reverse_train_direction; + } + + if (v->reverse_distance > 1) { + uint16 spd = ReversingDistanceTargetSpeed(v); + if (spd < v->cur_speed) v->cur_speed = spd; + } + /* For every vehicle after and including the given vehicle */ for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) { DiagDirection enterdir = DIAGDIR_BEGIN; @@ -3377,6 +3404,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) /* Inside depot */ gp.x = v->x_pos; gp.y = v->y_pos; + v->reverse_distance = 0; } else { /* Not inside depot */ @@ -3540,6 +3568,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (v->IsFrontEngine() && v->force_proceed == 0) { if (IsTunnelBridgeWithSignRed(gp.new_tile)) { v->cur_speed = 0; + v->vehstatus |= VS_TRAIN_SLOWING; return false; } if (IsTunnelBridgeExit(gp.new_tile)) { @@ -3628,6 +3657,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (IsToCloseBehindTrain(v, gp.new_tile, distance == 0)) { if (distance == 0) v->wait_counter = 0; v->cur_speed = 0; + v->vehstatus |= VS_TRAIN_SLOWING; return false; } /* flip signal in front to red on bridges*/ @@ -3688,6 +3718,9 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); + if (v->reverse_distance > 1) { + v->reverse_distance--; + } /* update the Z position of the vehicle */ int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index b85b265665..f080b20923 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -146,7 +146,9 @@ void VehicleServiceInDepot(Vehicle *v) NOT_REACHED(); } assert(type != INVALID_EXPENSES); - Money repair_cost = (v->breakdowns_since_last_service * v->repair_cost / _settings_game.vehicle.repair_cost) + 1; + + // The static cast is to fix compilation on (old) MSVC as the overload for OverflowSafeInt operator / is ambiguous. + Money repair_cost = (v->breakdowns_since_last_service * v->repair_cost / static_cast(_settings_game.vehicle.repair_cost)) + 1; CommandCost cost(type, repair_cost); v->First()->profit_this_year -= cost.GetCost() << 8; SubtractMoneyFromCompany(cost); @@ -1611,6 +1613,9 @@ void AgeVehicle(Vehicle *v) * @param front The front vehicle of the consist to check. * @param colour The string to show depending on if we are unloading or loading * @return A percentage of how full the Vehicle is. + * Percentages are rounded towards 50%, so that 0% and 100% are only returned + * if the vehicle is completely empty or full. + * This is useful for both display and conditional orders. */ uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour) { @@ -1658,7 +1663,13 @@ uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour) if (max == 0) return 100; /* Return the percentage */ - return (count * 100) / max; + if (count * 2 < max) { + /* Less than 50%; round up, so that 0% means really empty. */ + return CeilDiv(count * 100, max); + } else { + /* More than 50%; round down, so that 100% means really full. */ + return (count * 100) / max; + } } /** @@ -1683,6 +1694,7 @@ void VehicleEnterDepot(Vehicle *v) t->force_proceed = TFP_NONE; ClrBit(t->flags, VRF_TOGGLE_REVERSE); t->ConsistChanged(CCF_ARRANGE); + t->reverse_distance = 0; break; } @@ -2456,9 +2468,11 @@ void Vehicle::LeaveStation() if (old_occupancy == 0) { new_occupancy = current_occupancy; } else { + Company *owner = Company::GetIfValid(this->owner); + uint8 occupancy_smoothness = owner ? owner->settings.order_occupancy_smoothness : 0; // Exponential weighted moving average using occupancy_smoothness - new_occupancy = (old_occupancy - 1) * _settings_game.order.occupancy_smoothness; - new_occupancy += current_occupancy * (100 - _settings_game.order.occupancy_smoothness); + new_occupancy = (old_occupancy - 1) * occupancy_smoothness; + new_occupancy += current_occupancy * (100 - occupancy_smoothness); new_occupancy += 50; // round to nearest integer percent, rather than just floor new_occupancy /= 100; } @@ -2799,6 +2813,8 @@ static void SpawnAdvancedVisualEffect(const Vehicle *v) } } +uint16 ReversingDistanceTargetSpeed(const Train *v); + /** * Draw visual effects (smoke and/or sparks) for a vehicle chain. * @pre this->IsPrimaryVehicle() @@ -2827,10 +2843,12 @@ void Vehicle::ShowVisualEffect() const /* For trains, do not show any smoke when: * - the train is reversing * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed + * - is approaching a reversing point and its speed is equal to maximum approach speed */ if (HasBit(t->flags, VRF_REVERSING) || (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) && - t->cur_speed >= max_speed)) { + t->cur_speed >= max_speed) || + (t->reverse_distance >= 1 && t->cur_speed >= ReversingDistanceTargetSpeed(t))) { return; } } diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 1590647c0c..45f7f3d616 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -386,8 +386,10 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, bool auto_refit_allowed; CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cid, actual_subtype, &auto_refit_allowed); - if (auto_refit && !auto_refit_allowed) { - /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total. */ + if (auto_refit && (flags & DC_QUERY_COST) == 0 && !auto_refit_allowed) { + /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total. + * When querrying cost/capacity (for example in order refit GUI), we always assume 'allowed'. + * It is not predictable. */ total_capacity -= amount; total_mail_capacity -= mail_capacity; @@ -474,8 +476,15 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint /* Don't allow shadows and such to be refitted. */ if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR; + /* Allow auto-refitting only during loading and normal refitting only in a depot. */ - if (!free_wagon && (!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + if ((flags & DC_QUERY_COST) == 0 && // used by the refit GUI, including the order refit GUI. + !free_wagon && // used by autoreplace/renew + (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations + !front->IsStoppedInDepot()) { // refit inside depots + return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + } + if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); /* Check cargo */ diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index f0dd3cf536..665f79bd7a 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -754,7 +754,10 @@ struct RefitWindow : public Window { if (_returned_mail_refit_capacity > 0) { SetDParam(2, CT_MAIL); SetDParam(3, _returned_mail_refit_capacity); - if (money <= 0) { + if (this->order != INVALID_VEH_ORDER_ID) { + /* No predictable cost */ + return STR_PURCHASE_INFO_AIRCRAFT_CAPACITY; + } else if (money <= 0) { SetDParam(4, -money); return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT; } else { @@ -762,7 +765,11 @@ struct RefitWindow : public Window { return STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT; } } else { - if (money <= 0) { + if (this->order != INVALID_VEH_ORDER_ID) { + /* No predictable cost */ + SetDParam(2, STR_EMPTY); + return STR_PURCHASE_INFO_CAPACITY; + } else if (money <= 0) { SetDParam(2, -money); return STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT; } else { diff --git a/src/viewport.cpp b/src/viewport.cpp index 09100f61a7..1f02472a1b 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -99,6 +99,7 @@ #include "gui.h" #include +#include #include "table/strings.h" #include "table/string_colours.h" @@ -198,6 +199,26 @@ uint _vp_route_step_height_middle = 0; uint _vp_route_step_height_bottom = 0; SubSprite _vp_route_step_subsprite; +struct DrawnPathRouteTileLine { + TileIndex from_tile; + TileIndex to_tile; + + bool operator==(const DrawnPathRouteTileLine &other) const + { + return this->from_tile == other.from_tile && this->to_tile == other.to_tile; + } + + bool operator!=(const DrawnPathRouteTileLine &other) const + { + return !(*this == other); + } +}; + +std::vector _vp_route_paths_drawn_dirty; +std::vector _vp_route_paths_last_mark_dirty; + +static void MarkRoutePathsDirty(const std::vector &lines); + TileHighlightData _thd; static TileInfo *_cur_ti; bool _draw_bounding_boxes = false; @@ -1650,13 +1671,31 @@ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) { Order *order; const Vehicle *veh = GetVehicleFromWindow(_focused_window); - if (!veh) return; + if (!veh) { + if (!_vp_route_paths_drawn_dirty.empty()) { + // make sure we remove any leftover paths + MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); + _vp_route_paths_drawn_dirty.clear(); + DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 0"); + } + return; + } switch (_settings_client.gui.show_vehicle_route) { /* case 0: return; // No */ case 1: { // Simple TileIndex from_tile = GetLastValidOrderLocation(veh); - if (from_tile == INVALID_TILE) return; + if (from_tile == INVALID_TILE) { + if (!_vp_route_paths_drawn_dirty.empty()) { + // make sure we remove any leftover paths + MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); + _vp_route_paths_drawn_dirty.clear(); + DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 1"); + } + return; + } + + std::vector drawn_paths; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &_dpi_for_text; @@ -1680,10 +1719,26 @@ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) } GfxDrawLine(from_x, from_y, to_x, to_y, (final_order == order) ? PC_WHITE : PC_YELLOW, line_width, _settings_client.gui.dash_level_of_route_lines); + DrawnPathRouteTileLine path = { from_tile, to_tile }; + drawn_paths.push_back(path); + const OrderType ot = order->GetType(); if (ot == OT_GOTO_STATION || ot == OT_GOTO_DEPOT || ot == OT_GOTO_WAYPOINT || ot == OT_IMPLICIT) from_tile = to_tile; } + if (!_vp_route_paths_drawn_dirty.empty() && _vp_route_paths_drawn_dirty != drawn_paths) { + // make sure we remove any leftover paths + MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); + DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 2"); + } + if (_vp_route_paths_last_mark_dirty != drawn_paths) { + // make sure we're not drawing a partial path + MarkRoutePathsDirty(drawn_paths); + DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 3"); + } + + _vp_route_paths_drawn_dirty.swap(drawn_paths); // move + _cur_dpi = old_dpi; break; } @@ -2760,10 +2815,15 @@ void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile) assert(from_tile != INVALID_TILE); assert(to_tile != INVALID_TILE); - int x1 = TileX(from_tile); - int y1 = TileY(from_tile); - const int x2 = TileX(to_tile); - const int y2 = TileY(to_tile); + const Point from_pt = RemapCoords2(TileX(from_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(from_tile) * TILE_SIZE + TILE_SIZE / 2); + const Point to_pt = RemapCoords2(TileX(to_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(to_tile) * TILE_SIZE + TILE_SIZE / 2); + + const int block_radius = 20; + + int x1 = from_pt.x / block_radius; + int y1 = from_pt.y / block_radius; + const int x2 = to_pt.x / block_radius; + const int y2 = to_pt.y / block_radius; /* http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Simplification */ const int dx = abs(x2 - x1); @@ -2772,7 +2832,13 @@ void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile) const int sy = (y1 < y2) ? 1 : -1; int err = dx - dy; for (;;) { - MarkTileDirtyByTile(TileXY(x1, y1)); + MarkAllViewportsDirty( + (x1 - 1) * block_radius, + (y1 - 1) * block_radius, + (x1 + 1) * block_radius, + (y1 + 1) * block_radius, + ZOOM_LVL_END + ); if (x1 == x2 && y1 == y2) break; const int e2 = 2 * err; if (e2 > -dy) { @@ -2786,6 +2852,13 @@ void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile) } } +static void MarkRoutePathsDirty(const std::vector &lines) +{ + for (std::vector::const_iterator it = lines.begin(); it != lines.end(); ++it) { + MarkTileLineDirty(it->from_tile, it->to_tile); + } +} + void MarkAllRoutePathsDirty(const Vehicle *veh) { Order *order; @@ -2795,6 +2868,9 @@ void MarkAllRoutePathsDirty(const Vehicle *veh) return; case 1: // Simple + MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); + _vp_route_paths_drawn_dirty.clear(); + std::vector dirtied_paths; from_tile = GetLastValidOrderLocation(veh); if (from_tile == INVALID_TILE) return; FOR_VEHICLE_ORDERS(veh, order) { @@ -2803,8 +2879,11 @@ void MarkAllRoutePathsDirty(const Vehicle *veh) if (to_tile == INVALID_TILE) continue; MarkTileLineDirty(from_tile, to_tile); const OrderType ot = order->GetType(); + DrawnPathRouteTileLine path = { from_tile, to_tile }; + dirtied_paths.push_back(path); if (ot == OT_GOTO_STATION || ot == OT_GOTO_DEPOT || ot == OT_GOTO_WAYPOINT || ot == OT_IMPLICIT) from_tile = to_tile; } + _vp_route_paths_last_mark_dirty.swap(dirtied_paths); break; } } diff --git a/src/widgets/departures_widget.h b/src/widgets/departures_widget.h index e39b4d6cdf..3b2fc68396 100644 --- a/src/widgets/departures_widget.h +++ b/src/widgets/departures_widget.h @@ -7,16 +7,16 @@ * 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 waypoint_widget.h Types related to the waypoint widgets. */ +/** @file departures_widget.h Types related to the departures widgets. */ #ifndef WIDGETS_DEPARTURES_WIDGET_H #define WIDGETS_DEPARTURES_WIDGET_H /** Widgets of the WC_DEPARTURES_BOARD. */ enum DeparturesWindowWidgets { - WID_DB_CAPTION, ///< Window caption - WID_DB_LIST, ///< List of departures - WID_DB_SCROLLBAR, ///< List scrollbar + WID_DB_CAPTION, ///< Window caption + WID_DB_LIST, ///< List of departures + WID_DB_SCROLLBAR, ///< List scrollbar WID_DB_SHOW_DEPS, ///< Toggle departures button WID_DB_SHOW_ARRS, ///< Toggle arrivals button WID_DB_SHOW_VIA, ///< Toggle via button diff --git a/src/widgets/order_widget.h b/src/widgets/order_widget.h index fade59c3ea..c35182d925 100644 --- a/src/widgets/order_widget.h +++ b/src/widgets/order_widget.h @@ -29,6 +29,7 @@ enum OrderWidgets { WID_O_SERVICE, ///< Select service (at depot). WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner. WID_O_REFIT_DROPDOWN, ///< Open refit options. + WID_O_REVERSE, ///< Select waypoint reverse type WID_O_COND_VARIABLE, ///< Choose condition variable. WID_O_COND_COMPARATOR, ///< Choose condition type. WID_O_COND_VALUE, ///< Choose condition value. diff --git a/src/window.cpp b/src/window.cpp index 7999eb0999..dd8da4ad3f 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1207,6 +1207,7 @@ void ChangeWindowOwner(Owner old_owner, Owner new_owner) case WC_BUY_COMPANY: case WC_COMPANY: case WC_COMPANY_INFRASTRUCTURE: + case WC_VEHICLE_ORDERS: // Changing owner would also require changing WindowDesc, which is not possible; however keeping the old one crashes because of missing widgets etc.. See ShowOrdersWindow(). continue; default: diff --git a/src/zoom_func.h b/src/zoom_func.h index 1cb3d0c486..da266e35c6 100644 --- a/src/zoom_func.h +++ b/src/zoom_func.h @@ -67,7 +67,7 @@ static inline int UnScaleByZoomLower(int value, ZoomLevel zoom) /** * Short-hand to apply GUI zoom level. * @param value Pixel amount at #ZOOM_LVL_BEGIN (full zoom in). - * @return value Pixel amount at #ZOOM_LVL_GUI. + * @return Pixel amount at #ZOOM_LVL_GUI (current interface size). */ static inline int UnScaleGUI(int value) { @@ -76,8 +76,8 @@ static inline int UnScaleGUI(int value) /** * Scale traditional pixel dimensions to GUI zoom level. - * @param value Pixel amount at 1x zoom level. - * @return value Pixel amount at #ZOOM_LVL_GUI. + * @param value Pixel amount at #ZOOM_LVL_BASE (traditional "normal" interface size). + * @return Pixel amount at #ZOOM_LVL_GUI (current interface size). */ static inline int ScaleGUITrad(int value) {