diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 1b45c22fb2..dcd7a8081a 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -315,6 +315,77 @@ jobs: cmake --build . echo "::endgroup::" + msys2: + name: msys2 + + strategy: + fail-fast: false + matrix: + include: + - msystem: MINGW64 + arch: x86_64 + - msystem: MINGW32 + arch: i686 + + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.msystem }} + release: false + install: >- + git + make + mingw-w64-${{ matrix.arch }}-cmake + mingw-w64-${{ matrix.arch }}-gcc + mingw-w64-${{ matrix.arch }}-lzo2 + mingw-w64-${{ matrix.arch }}-libpng + + - name: Install OpenGFX + shell: bash + run: | + mkdir -p "C:/Users/Public/Documents/OpenTTD/baseset" + cd "C:/Users/Public/Documents/OpenTTD/baseset" + + echo "::group::Download OpenGFX" + curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip + echo "::endgroup::" + + echo "::group::Unpack OpenGFX" + unzip opengfx-all.zip + echo "::endgroup::" + + rm -f opengfx-all.zip + + - name: Install GCC problem matcher + uses: ammaraskar/gcc-problem-matcher@master + + - name: Build + shell: msys2 {0} + run: | + mkdir build + cd build + + echo "::group::CMake" + cmake .. -G"MSYS Makefiles" + echo "::endgroup::" + + echo "::group::Build" + echo "Running on $(nproc) cores" + cmake --build . -j $(nproc) + echo "::endgroup::" + + - name: Test + shell: msys2 {0} + run: | + cd build + ctest -j $(nproc) --timeout 120 + check_annotations: name: Check Annotations needs: @@ -322,6 +393,7 @@ jobs: - linux - macos - windows + - msys2 if: always() && github.event_name == 'pull_request' diff --git a/CMakeLists.txt b/CMakeLists.txt index d0e029607c..c147e9184b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -433,6 +433,7 @@ if(WIN32) -DUNICODE -D_UNICODE -DWITH_UNISCRIBE + -DPSAPI_VERSION=1 ) target_link_libraries(openttd @@ -440,6 +441,7 @@ if(WIN32) winmm imm32 usp10 + psapi ) endif() diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp index c8548bac36..2baca100e0 100644 --- a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp @@ -79,7 +79,7 @@ SQInstructionDesc g_InstrDesc[]={ {"_OP_NEWSLOTA"}, {"_OP_SCOPE_END"} }; -#endif + void DumpLiteral(SQObjectPtr &o) { switch(type(o)){ @@ -90,6 +90,7 @@ void DumpLiteral(SQObjectPtr &o) default: printf("(%s %p)",GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler } } +#endif SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) { diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index e54f628297..2f6c95aaad 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -483,7 +483,7 @@ public: break; case WID_AP_AIRPORT_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; + int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; if (num_clicked >= this->vscroll->GetCount()) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 5dad2c9126..be2c5782f9 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -1064,7 +1064,7 @@ struct DepotWindow : Window { this->RaiseWidget(WID_D_SELL); this->SetWidgetDirty(WID_D_SELL); } - if (this->nested_array[WID_D_SELL] != nullptr && !this->IsWidgetDisabled(WID_D_SELL_CHAIN)) { + if (this->GetWidget(WID_D_SELL) != nullptr && !this->IsWidgetDisabled(WID_D_SELL_CHAIN)) { this->RaiseWidget(WID_D_SELL_CHAIN); this->SetWidgetDirty(WID_D_SELL_CHAIN); } diff --git a/src/error.h b/src/error.h index 5519013be1..2d4a194cff 100644 --- a/src/error.h +++ b/src/error.h @@ -53,6 +53,7 @@ public: void SetDParam(uint n, uint64 v); void SetDParamStr(uint n, const char *str); + void SetDParamStr(uint n, const std::string &str); void CopyOutDParams(); }; diff --git a/src/error_gui.cpp b/src/error_gui.cpp index d531ad8c89..c00c61ed0b 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -166,6 +166,16 @@ void ErrorMessageData::SetDParamStr(uint n, const char *str) this->strings[n] = stredup(str); } +/** + * Set a rawstring parameter. + * @param n Parameter index + * @param str Raw string + */ +void ErrorMessageData::SetDParamStr(uint n, const std::string &str) +{ + this->SetDParamStr(n, str.c_str()); +} + /** Define a queue with errors. */ typedef std::list ErrorList; /** The actual queue with errors. */ diff --git a/src/gfx.cpp b/src/gfx.cpp index b793b89202..3efa2524c3 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -908,6 +908,21 @@ Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize) return layout.GetBounds(); } +/** + * Return the string dimension in pixels. The height and width are returned + * in a single Dimension value. TINYFONT, BIGFONT modifiers are only + * supported as the first character of the string. The returned dimensions + * are therefore a rough estimation correct for all the current strings + * but not every possible combination + * @param str string to calculate pixel-width + * @param start_fontsize Fontsize to start the text with + * @return string width and height in pixels + */ +Dimension GetStringBoundingBox(const std::string &str, FontSize start_fontsize) +{ + return GetStringBoundingBox(str.c_str(), start_fontsize); +} + /** * Get bounding box of a string. Uses parameters set by #SetDParam if needed. * Has the same restrictions as #GetStringBoundingBox(const char *str, FontSize start_fontsize). diff --git a/src/gfx_func.h b/src/gfx_func.h index 2a7ec27ab0..db95c1d26e 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -107,6 +107,7 @@ void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); +Dimension GetStringBoundingBox(const std::string &str, FontSize start_fontsize = FS_NORMAL); Dimension GetStringBoundingBox(StringID strid); int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); int GetStringHeight(StringID str, int maxw); diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 6834fd2d2b..43c14251b9 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -890,6 +890,11 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}A oferta do subsídio expirou:{}{}{STRING} de {STRING} para {STRING} agora não irá atrair um subsídio STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsídio removido:{}{} Serviço de {STRING} de {STRING} para {STRING} não é mais subsidiado +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Subsídio de serviço oferecido:{}{}Primeiro serviço de {STRING} de {STRING} para {STRING} atrairá subsídio de {NUM} anos da autoridade local! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subsídio de serviço concedido à {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} pagará 50% extra durante o{P 4 "" s} próximo{P 4 "" s} {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido à {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} pagará o dobro de tarifas durante o{P 4 "" s} próximo{P 4 "" s} {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido à {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} pagará o triplo de tarifas durante o{P 4 "" s} próximo{P 4 "" s} {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido à {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} pagará o quádruplo de tarifas durante o{P 4 "" s} próximo{P 4 "" s} {NUM} ano{P "" s}! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Tráfego caótico em {TOWN}!{}{} Programa de reconstrução rodoviária financiado por {STRING} provoca 6 meses de miséria aos condutores! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Monopólio dos transportes! @@ -1205,6 +1210,10 @@ STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Quebra de veíc STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Controla o quanto veículos mal conservados podem quebrar STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Multiplicador de subsídios: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Define quando é pago por conexões subsidiadas +STR_CONFIG_SETTING_SUBSIDY_DURATION :Duração do subsídio: {STRING} +STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT :Defina por quantos anos o subsídio é concedido +STR_CONFIG_SETTING_SUBSIDY_DURATION_VALUE :{NUM} ano{P "" s} +STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sem subsídios STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Custos de construção: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Define o nível de construção e custos de compra STR_CONFIG_SETTING_RECESSIONS :Recessões: {STRING} diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 7276830e36..53e6eff96b 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -887,7 +887,7 @@ STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} ottaa nyt vastaan {STRING}. STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} ottaa nyt vastaan {STRING} ja {STRING}. -STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Tukitarjous päättynyt:{}{}{STRING} välillä {STRING} - {STRING} ei voi enää saada tukea +STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Tukitarjous päättynyt:{}{}{STRING} välillä {STRING} – {STRING} ei voi enää saada tukea STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Tuki vedetty pois:{}{}{STRING} kuljetuspalvelu välille {STRING}-{STRING} ei ole enää tuettu STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Tuki tarjottu:{}{}Ensimmäinen {STRING}kuljetus välillä {STRING} – {STRING} saa {NUM} vuoden mittaisen tuen paikallisviranomaisilta! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Tuki myönnetty yhtiölle {STRING}!{}{}{STRING}kuljetus välillä {STRING} – {STRING} tuottaa 50{NBSP}% enemmän seuraavan {NUM} vuoden ajan! diff --git a/src/lang/german.txt b/src/lang/german.txt index a2d04121e4..1f51999f53 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -907,6 +907,11 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Subventionsangebot abgelaufen:{}{}{STRING}transport von {STRING} nach {STRING} wird nicht mehr subventioniert STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subventionsende:{}{}{STRING}transport von {STRING} nach {STRING} wird nicht mehr subventioniert +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Subventionsangebot:{}{}Erster {STRING}transport von {STRING} nach {STRING} wird {NUM} Jahr{P "" e} von den örtlichen Behörden subventioniert! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subvention vergeben an {STRING}!{}{}{STRING}transport von {STRING} nach {STRING} erhält für {NUM} Jahr{P "" e} einen 50% höheren Preis! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subvention vergeben an {STRING}!{}{}{STRING}transport von {STRING} nach {STRING} erhält für {NUM} Jahr{P "" e} den doppelten Preis! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subvention vergeben an {STRING}!{}{}{STRING}transport von {STRING} nach {STRING} erhält für {NUM} Jahr{P "" e} den dreifachen Preis! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subvention vergeben an {STRING}!{}{}{STRING}transport von {STRING} nach {STRING} erhält für {NUM} Jahr{P "" e} den vierfachen Preis! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Verkehrschaos in {TOWN}!{}{}Straßensanierungsprogramm finanziert durch {STRING} wird 6 Monate lang Verzögerungen im Verkehr bewirken! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transportmonopol! @@ -1222,6 +1227,10 @@ STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Fahrzeugpannen: STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Einstellen, wie oft unzureichend gewartete Fahrzeuge Pannen haben können STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subventions-Multiplikator: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Einstellen, wieviel für subventionierte Verbindungen gezahlt wird +STR_CONFIG_SETTING_SUBSIDY_DURATION :Subventionsdauer: {STRING} +STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT :Die Anzahl der Jahre, für die eine Subvention vergeben wird +STR_CONFIG_SETTING_SUBSIDY_DURATION_VALUE :{NUM} Jahr{P "" e} +STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Keine Subventionen STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Baukosten: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Höhe der Bau- und Einkaufskosten festlegen STR_CONFIG_SETTING_RECESSIONS :Rezessionen: {STRING} diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 717dbf17bb..82094c7546 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -890,6 +890,11 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Oferta de subsídio expirou:{}{}Ligação de {STRING} d{G 1 e o a os as} {STRING} para{G 2 "" " o" " a" " os" " as"} {STRING} já não será subsidiada. STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsídio retirado:{}{}Ligação de {STRING} d{G 1 e o a os as} {STRING} para{G 2 "" " o" " a" " os" " as"} {STRING} já não é subsidiada. +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Subsídio de ligação oferecido:{}{}Primeiro serviço de {STRING} de {STRING} para {STRING} atrairá {NUM} ano{P "" s} de subsídio da autoridade local! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subsídio de serviço concedido a {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} será pago a 50% extra durante {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido a {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} será pago a 200% durante {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido a {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} será pago a 300% durante {NUM} ano{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subsídio de serviço concedido a {STRING}!{}{}Serviço de {STRING} de {STRING} para {STRING} será pago a 400% durante {NUM} ano{P "" s}! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Tráfego caótico em {TOWN}!{}{}Programa de reconstrução de estradas financiado por {STRING} provoca 6 meses de miséria aos condutores! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Monopólio de Transporte! @@ -1205,6 +1210,10 @@ STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Avarias de veí STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Controla quão frequentemente veículos inadequadamento mantidos podem avariar STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Multiplicador de subsídio: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Define quanto é pago para ligações subsidiadas +STR_CONFIG_SETTING_SUBSIDY_DURATION :Duração do subsídio: {STRING} +STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT :Define o número de anos de concessão de um subsídio +STR_CONFIG_SETTING_SUBSIDY_DURATION_VALUE :{NUM} ano{P "" s} +STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sem subsídios STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Custos de construção: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Configurar o nível de construção e custos de compra STR_CONFIG_SETTING_RECESSIONS :Recessões: {STRING} diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 32225ef75e..bfc659b6fa 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -2213,7 +2213,7 @@ STR_NETWORK_ERROR_CLIENT_START :{WHITE}No se pu STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tiempo de espera agotado en conexión #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Se ha producido un error de protocolo y la conexión ha sido cerrada STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}No se ha establecido tu nombre de jugador. El nombre se puede establecer en la parte superior de la ventana de Multijugador -STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE}El nombre de tu servidor no se ha definido. El nombre puede definirse al principio de la ventana de Multijugador +STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE}No se ha establecido el nombre de tu servidor. El nombre se puede establecer en la parte superior de la ventana de Multijugador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La versión de este cliente no corresponde con la versión del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contraseña incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor está completo diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 1270895c3b..652a74f7c4 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -890,6 +890,11 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Oferta de subsidio vencida:{}{}{STRING} de {STRING} a {STRING} ya no está subsidiado STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidio retirado:{}{}El servicio de {STRING} de {STRING} hacia {STRING} ya no está subsidiado +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Se ofrece subsidio.{}{}¡El primer servicio de {STRING} desde {STRING} a {STRING} tendrá subsidio de {NUM} año{P "" s} por parte del ayuntamiento local! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}¡Subsidio otorgado a {STRING}!{}{}¡El servicio de {STRING} desde {STRING} a {STRING} generará un 50% extra por {NUM} año{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}¡Subsidio otorgado a {STRING}!{}{}¡El servicio de {STRING} desde {STRING} a {STRING} generará tasa doble por {NUM} año{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}¡Subsidio otorgado a {STRING}!{}{}¡El servicio de {STRING} desde {STRING} a {STRING} generará tasa triple por {NUM} año{P "" s}! +STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}¡Subsidio otorgado a {STRING}!{}{}¡El servicio de {STRING} desde {STRING} a {STRING} generará tasa cuádruple por {NUM} año{P "" s}! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}¡Caos por el tráfico en {TOWN}!{}{}¡Obras de reconstrucción de caminos por parte de {STRING} provocan 6 meses de dolores de cabeza a conductores! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}¡Monopolio de transportes! @@ -1205,6 +1210,10 @@ STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Averías de veh STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Controlar cada cuánto los vehículos con poco mantenimiento sufren fallas STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Multiplicador de subsidio: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Establecer cuánto se paga por subsidios conectados +STR_CONFIG_SETTING_SUBSIDY_DURATION :Duración de subsidio: {STRING} +STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT :Años que durará un subsidio otorgado +STR_CONFIG_SETTING_SUBSIDY_DURATION_VALUE :{NUM} año{P "" s} +STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sin subsidios STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costos de construcción: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Nivel de costos de construcción y adquisición STR_CONFIG_SETTING_RECESSIONS :Recesiones: {STRING} diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 2a3695ddb1..e1db7d4773 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -2119,7 +2119,9 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Danh sách máy STR_NETWORK_COMPANY_LIST_SPECTATE :Xem # Network client list +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Gia nhập công ty này +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Cấm STR_NETWORK_SERVER :Server diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 486b6e64ee..e76833c91a 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -34,6 +34,9 @@ #include "table/strings.h" +#include +#include + #include "safeguards.h" /** Method to open the OSK. */ @@ -63,16 +66,10 @@ static WindowDesc _land_info_desc( ); class LandInfoWindow : public Window { - enum LandInfoLines { - LAND_INFO_CENTERED_LINES = 32, ///< Up to 32 centered lines (arbitrary limit) - LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line - LAND_INFO_LINE_END, - }; - - static const uint LAND_INFO_LINE_BUFF_SIZE = 512; + StringList landinfo_data; ///< Info lines to show. + std::string cargo_acceptance; ///< Centered multi-line string for cargo acceptance. public: - char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE]; TileIndex tile; void DrawWidget(const Rect &r, int widget) const override @@ -80,16 +77,14 @@ public: if (widget != WID_LI_BACKGROUND) return; uint y = r.top + WD_TEXTPANEL_TOP; - for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { - if (StrEmpty(this->landinfo_data[i])) break; - + for (size_t i = 0; i < this->landinfo_data.size(); i++) { DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_HOR_CENTER); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (i == 0) y += 4; } - if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { - SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + if (!this->cargo_acceptance.empty()) { + SetDParamStr(0, this->cargo_acceptance); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); } } @@ -99,9 +94,7 @@ public: if (widget != WID_LI_BACKGROUND) return; size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; - for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { - if (StrEmpty(this->landinfo_data[i])) break; - + for (size_t i = 0; i < this->landinfo_data.size(); i++) { uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = std::max(size->width, width); @@ -109,10 +102,10 @@ public: if (i == 0) size->height += 4; } - if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { - uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + if (!this->cargo_acceptance.empty()) { + uint width = GetStringBoundingBox(this->cargo_acceptance).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = std::max(size->width, std::min(300u, width)); - SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + SetDParamStr(0, cargo_acceptance); size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); } } @@ -199,13 +192,12 @@ public: AddAcceptedCargo(tile, acceptance, nullptr); GetTileDesc(tile, &td); - uint line_nr = 0; + this->landinfo_data.clear(); /* Tiletype */ SetDParam(0, td.dparam[0]); SetDParam(1, td.dparam[1]); - GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(td.str)); /* Up to four owners */ for (uint i = 0; i < 4; i++) { @@ -213,8 +205,7 @@ public: SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A); if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile); - GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(td.owner_type[i])); } /* Cost to clear/revenue when cleared */ @@ -234,18 +225,18 @@ public: SetDParam(0, cost); } } - GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(str)); /* Location */ - char tmp[16]; - seprintf(tmp, lastof(tmp), "0x%.4X", tile); + std::stringstream tile_ss; + tile_ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << tile; // 0x%.4X + std::string tile_str = tile_ss.str(); // Can't pass it directly to SetDParamStr as the string is only a temporary and would be destructed before the GetString call. + SetDParam(0, TileX(tile)); SetDParam(1, TileY(tile)); SetDParam(2, GetTileZ(tile)); - SetDParamStr(3, tmp); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr])); - line_nr++; + SetDParamStr(3, tile_str); + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_LANDINFO_COORDS)); /* Local authority */ SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); @@ -253,140 +244,124 @@ public: SetDParam(0, STR_TOWN_NAME); SetDParam(1, t->index); } - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY)); /* Build date */ if (td.build_date != INVALID_DATE) { SetDParam(0, td.build_date); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_BUILD_DATE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_BUILD_DATE)); } /* Station class */ if (td.station_class != STR_NULL) { SetDParam(0, td.station_class); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_CLASS, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_STATION_CLASS)); } /* Station type name */ if (td.station_name != STR_NULL) { SetDParam(0, td.station_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_STATION_TYPE)); } /* Airport class */ if (td.airport_class != STR_NULL) { SetDParam(0, td.airport_class); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_CLASS, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_AIRPORT_CLASS)); } /* Airport name */ if (td.airport_name != STR_NULL) { SetDParam(0, td.airport_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_AIRPORT_NAME)); } /* Airport tile name */ if (td.airport_tile_name != STR_NULL) { SetDParam(0, td.airport_tile_name); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME)); } /* Rail type name */ if (td.railtype != STR_NULL) { SetDParam(0, td.railtype); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_TYPE)); } /* Rail speed limit */ if (td.rail_speed != 0) { SetDParam(0, td.rail_speed); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT)); } /* 2nd Rail type name */ if (td.railtype2 != STR_NULL) { SetDParam(0, td.railtype2); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_TYPE)); } /* 2nd Rail speed limit */ if (td.rail_speed2 != 0) { SetDParam(0, td.rail_speed2); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT)); } /* Road type name */ if (td.roadtype != STR_NULL) { SetDParam(0, td.roadtype); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_ROAD_TYPE)); } /* Road speed limit */ if (td.road_speed != 0) { SetDParam(0, td.road_speed); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT)); } /* Tram type name */ if (td.tramtype != STR_NULL) { SetDParam(0, td.tramtype); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_TYPE, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_TRAM_TYPE)); } /* Tram speed limit */ if (td.tram_speed != 0) { SetDParam(0, td.tram_speed); - GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT)); } /* NewGRF name */ if (td.grf != nullptr) { SetDParamStr(0, td.grf); - GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); - line_nr++; + this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_NEWGRF_NAME)); } - assert(line_nr < LAND_INFO_CENTERED_LINES); - - /* Mark last line empty */ - this->landinfo_data[line_nr][0] = '\0'; - /* Cargo acceptance is displayed in a extra multiline */ - char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); - bool found = false; + std::stringstream line; + line << GetString(STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED); + bool found = false; for (CargoID i = 0; i < NUM_CARGO; ++i) { if (acceptance[i] > 0) { /* Add a comma between each item. */ - if (found) strp = strecpy(strp, ", ", lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + if (found) line << ", "; found = true; /* If the accepted value is less than 8, show it in 1/8:ths */ if (acceptance[i] < 8) { SetDParam(0, acceptance[i]); SetDParam(1, CargoSpec::Get(i)->name); - strp = GetString(strp, STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + line << GetString(STR_LAND_AREA_INFORMATION_CARGO_EIGHTS); } else { - strp = GetString(strp, CargoSpec::Get(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + line << GetString(CargoSpec::Get(i)->name); } } } - if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; + if (found) { + this->cargo_acceptance = line.str(); + } else { + this->cargo_acceptance.clear(); + } } bool IsNewGRFInspectable() const override diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp index e43775a5a5..b75c8e207e 100644 --- a/src/network/core/os_abstraction.cpp +++ b/src/network/core/os_abstraction.cpp @@ -20,6 +20,9 @@ #include "os_abstraction.h" #include "../../string_func.h" #include +#if defined(__MINGW32__) +#include "../../3rdparty/mingw-std-threads/mingw.mutex.h" +#endif #include "../../safeguards.h" diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 1348039a91..035da4361f 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -21,6 +21,9 @@ #include #include #include +#if defined(__MINGW32__) +#include "3rdparty/mingw-std-threads/mingw.thread.h" +#endif /** The states of sending the packets. */ enum SendPacketsState { diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4f6dcdcef1..7a3cb37126 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -114,7 +114,7 @@ public: int skip_sprites; ///< Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file) /* Currently referenceable spritegroups */ - SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; + const SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; /** Clear temporary data before processing the next file in the current loading stage */ void ClearDataForNextFile() @@ -5211,7 +5211,7 @@ static void NewSpriteGroup(ByteReader *buf) * otherwise it specifies a number of entries, the exact * meaning depends on the feature * V feature-specific-data (huge mess, don't even look it up --pasky) */ - SpriteGroup *act_group = nullptr; + const SpriteGroup *act_group = nullptr; uint8 feature = buf->ReadByte(); if (feature >= GSF_END) { @@ -5398,24 +5398,53 @@ static void NewSpriteGroup(ByteReader *buf) break; } - assert(RealSpriteGroup::CanAllocateItem()); - RealSpriteGroup *group = new RealSpriteGroup(); - group->nfo_line = _cur.nfo_line; - act_group = group; - grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u loaded, %u loading", setid, num_loaded, num_loading); - for (uint i = 0; i < num_loaded; i++) { + if (num_loaded + num_loading == 1) { + /* Avoid creating 'Real' sprite group if only one option. */ uint16 spriteid = buf->ReadWord(); - group->loaded.push_back(CreateGroupFromGroupID(feature, setid, type, spriteid)); - grfmsg(8, "NewSpriteGroup: + rg->loaded[%i] = subset %u", i, spriteid); + act_group = CreateGroupFromGroupID(feature, setid, type, spriteid); + grfmsg(8, "NewSpriteGroup: one result, skipping RealSpriteGroup = subset %u", spriteid); + break; + } + + std::vector loaded; + std::vector loading; + + for (uint i = 0; i < num_loaded; i++) { + loaded.push_back(buf->ReadWord()); + grfmsg(8, "NewSpriteGroup: + rg->loaded[%i] = subset %u", i, loaded[i]); } for (uint i = 0; i < num_loading; i++) { - uint16 spriteid = buf->ReadWord(); - group->loading.push_back(CreateGroupFromGroupID(feature, setid, type, spriteid)); - grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid); + loading.push_back(buf->ReadWord()); + grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, loading[i]); + } + + if (std::adjacent_find(loaded.begin(), loaded.end(), std::not_equal_to<>()) == loaded.end() && + std::adjacent_find(loading.begin(), loading.end(), std::not_equal_to<>()) == loading.end() && + loaded[0] == loading[0]) + { + /* Both lists only contain the same value, so don't create 'Real' sprite group */ + act_group = CreateGroupFromGroupID(feature, setid, type, loaded[0]); + grfmsg(8, "NewSpriteGroup: same result, skipping RealSpriteGroup = subset %u", loaded[0]); + break; + } + + assert(RealSpriteGroup::CanAllocateItem()); + RealSpriteGroup *group = new RealSpriteGroup(); + group->nfo_line = _cur.nfo_line; + act_group = group; + + for (uint16 spriteid : loaded) { + const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid); + group->loaded.push_back(t); + } + + for (uint16 spriteid : loading) { + const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid); + group->loading.push_back(t); } break; diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index 3d08d2feae..bcb3416011 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -57,8 +57,6 @@ struct AirportResolverObject : public ResolverObject { } } - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override; uint32 GetDebugID() const override; }; @@ -219,16 +217,6 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available)); } -/* virtual */ const SpriteGroup *AirportResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - /* Airport action 2s should always have only 1 "loaded" state, but some - * times things don't follow the spec... */ - if (!group->loaded.empty()) return group->loaded[0]; - if (!group->loading.empty()) return group->loading[0]; - - return nullptr; -} - GrfSpecFeature AirportResolverObject::GetFeature() const { return GSF_AIRPORTS; diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index f5bbda6fb0..bf05963f82 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -49,8 +49,6 @@ struct CanalResolverObject : public ResolverObject { } } - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override; uint32 GetDebugID() const override; }; @@ -108,14 +106,6 @@ struct CanalResolverObject : public ResolverObject { return UINT_MAX; } - -/* virtual */ const SpriteGroup *CanalResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - if (group->loaded.empty()) return nullptr; - - return group->loaded[0]; -} - GrfSpecFeature CanalResolverObject::GetFeature() const { return GSF_CANALS; diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index 105a2b2524..70b1a18d94 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -19,22 +19,10 @@ struct CargoResolverObject : public ResolverObject { CargoResolverObject(const CargoSpec *cs, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override; uint32 GetDebugID() const override; }; -/* virtual */ const SpriteGroup *CargoResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - /* Cargo action 2s should always have only 1 "loaded" state, but some - * times things don't follow the spec... */ - if (!group->loaded.empty()) return group->loaded[0]; - if (!group->loading.empty()) return group->loading[0]; - - return nullptr; -} - GrfSpecFeature CargoResolverObject::GetFeature() const { return GSF_CARGOES; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index 5d235d42b8..1895fe78a3 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -954,7 +954,7 @@ struct SpriteAlignerWindow : Window { switch (widget) { case WID_SA_CAPTION: SetDParam(0, this->current_sprite); - SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename().c_str()); + SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename()); break; case WID_SA_OFFSETS_ABS: diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index 428b21ff9a..4c4630e1d9 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -63,8 +63,6 @@ struct GenericResolverObject : public ResolverObject { } } - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override { return (GrfSpecFeature)this->generic_scope.feature; @@ -147,14 +145,6 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g return UINT_MAX; } - -/* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - if (group->loaded.empty()) return nullptr; - - return group->loaded[0]; -} - /** * Generic resolver. * @param ai_callback Callback comes from the AI. diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 7ea1db3278..f0c60849d8 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -59,13 +59,6 @@ return UINT_MAX; } -/* virtual */ const SpriteGroup *RailTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - if (!group->loading.empty()) return group->loading[0]; - if (!group->loaded.empty()) return group->loaded[0]; - return nullptr; -} - GrfSpecFeature RailTypeResolverObject::GetFeature() const { return GSF_RAILTYPES; diff --git a/src/newgrf_railtype.h b/src/newgrf_railtype.h index 8b8eb63e23..afcae06a58 100644 --- a/src/newgrf_railtype.h +++ b/src/newgrf_railtype.h @@ -49,8 +49,6 @@ struct RailTypeResolverObject : public ResolverObject { } } - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override; uint32 GetDebugID() const override; }; diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp index 977924f633..cb20b7160e 100644 --- a/src/newgrf_roadtype.cpp +++ b/src/newgrf_roadtype.cpp @@ -58,13 +58,6 @@ return UINT_MAX; } -/* virtual */ const SpriteGroup *RoadTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const -{ - if (!group->loading.empty()) return group->loading[0]; - if (!group->loaded.empty()) return group->loaded[0]; - return nullptr; -} - GrfSpecFeature RoadTypeResolverObject::GetFeature() const { RoadType rt = GetRoadTypeByLabel(this->roadtype_scope.rti->label, false); diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h index 21f6bd0c8c..10331606db 100644 --- a/src/newgrf_roadtype.h +++ b/src/newgrf_roadtype.h @@ -40,8 +40,6 @@ struct RoadTypeResolverObject : public ResolverObject { } } - const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; - GrfSpecFeature GetFeature() const override; uint32 GetDebugID() const override; }; diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index c108755e8e..41ef4e1e8c 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -127,6 +127,9 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc */ /* virtual */ const SpriteGroup *ResolverObject::ResolveReal(const RealSpriteGroup *group) const { + if (!group->loaded.empty()) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; + return nullptr; } diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 897b94ad38..f00047aa93 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -519,7 +519,7 @@ public: { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; + int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; if (num_clicked >= (int)this->object_classes.size()) break; this->SelectOtherClass(this->object_classes[num_clicked]); diff --git a/src/openttd.cpp b/src/openttd.cpp index c39976f198..dc4a47cf04 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -877,7 +877,7 @@ int openttd_main(int argc, char *argv[]) BaseGraphics::SetSet({}); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); - msg.SetDParamStr(0, graphics_set.c_str()); + msg.SetDParamStr(0, graphics_set); ScheduleErrorMessage(msg); } } @@ -936,7 +936,7 @@ int openttd_main(int argc, char *argv[]) usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 1.4 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); - msg.SetDParamStr(0, sounds_set.c_str()); + msg.SetDParamStr(0, sounds_set); ScheduleErrorMessage(msg); } } @@ -948,7 +948,7 @@ int openttd_main(int argc, char *argv[]) usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 1.4 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); - msg.SetDParamStr(0, music_set.c_str()); + msg.SetDParamStr(0, music_set); ScheduleErrorMessage(msg); } } diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 2f728573b2..b8c4fc845b 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "../../safeguards.h" @@ -248,25 +249,19 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) /* virtual */ char *CrashLogWindows::LogModules(char *output, const char *last) const { MakeCRCTable(AllocaM(uint32, 256)); - BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD); - output += seprintf(output, last, "Module information:\n"); - if (LoadLibraryList((Function*)&EnumProcessModules, "psapi.dll\0EnumProcessModules\0\0")) { + HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); + if (proc != nullptr) { HMODULE modules[100]; DWORD needed; - BOOL res; - - HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); - if (proc != nullptr) { - res = EnumProcessModules(proc, modules, sizeof(modules), &needed); - CloseHandle(proc); - if (res) { - size_t count = std::min(needed / sizeof(HMODULE), lengthof(modules)); + BOOL res = EnumProcessModules(proc, modules, sizeof(modules), &needed); + CloseHandle(proc); + if (res) { + size_t count = std::min(needed / sizeof(HMODULE), lengthof(modules)); - for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]); - return output + seprintf(output, last, "\n"); - } + for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]); + return output + seprintf(output, last, "\n"); } } output = PrintModuleInfo(output, last, nullptr); @@ -746,7 +741,7 @@ static void CDECL CustomAbort(int signal) mov safe_esp, esp } # else - asm("movl %%esp, %0" : "=rm" ( safe_esp )); + asm("movl %%esp, %0" : "=rm" (safe_esp)); # endif _safe_esp = safe_esp; #endif diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index 6c0a9366e9..7c70557b61 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -144,7 +144,7 @@ void UniscribeResetScriptCache(FontSize size) /** Load the matching native Windows font. */ static HFONT HFontFromFont(Font *font) { - if (font->fc->GetOSHandle() != nullptr) return CreateFontIndirect((const PLOGFONT)font->fc->GetOSHandle()); + if (font->fc->GetOSHandle() != nullptr) return CreateFontIndirect(reinterpret_cast(const_cast(font->fc->GetOSHandle()))); LOGFONT logfont; ZeroMemory(&logfont, sizeof(LOGFONT)); diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 3c2ea2ff2b..a743719a84 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -40,6 +40,10 @@ #include "../../safeguards.h" +#ifdef __MINGW32__ +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif /* __MINGW32__ */ + static bool _has_console; static bool _cursor_disable = true; static bool _cursor_visible = true; @@ -781,38 +785,6 @@ int GetCurrentThreadName(char *str, const char *last) return 0; } -/** - * Is the current Windows version Vista or later? - * @return True if the current Windows is Vista or later. - */ -bool IsWindowsVistaOrGreater() -{ - typedef BOOL (WINAPI * LPVERIFYVERSIONINFO)(LPOSVERSIONINFOEX, DWORD, DWORDLONG); - typedef ULONGLONG (NTAPI * LPVERSETCONDITIONMASK)(ULONGLONG, DWORD, BYTE); -#ifdef UNICODE - static LPVERIFYVERSIONINFO _VerifyVersionInfo = (LPVERIFYVERSIONINFO)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerifyVersionInfoW"); -#else - static LPVERIFYVERSIONINFO _VerifyVersionInfo = (LPVERIFYVERSIONINFO)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerifyVersionInfoA"); -#endif - static LPVERSETCONDITIONMASK _VerSetConditionMask = (LPVERSETCONDITIONMASK)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerSetConditionMask"); - - if (_VerifyVersionInfo != nullptr && _VerSetConditionMask != nullptr) { - OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; - DWORDLONG dwlConditionMask = 0; - dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); - dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); - dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - - osvi.dwMajorVersion = 6; - osvi.dwMinorVersion = 0; - osvi.wServicePackMajor = 0; - - return _VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; - } else { - return LOBYTE(GetVersion()) >= 6; - } -} - #ifdef _MSC_VER /* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ const DWORD MS_VC_EXCEPTION = 0x406D1388; diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 3c9c16d4d4..d65bf78efd 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -25,6 +25,5 @@ wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen); void Win32SetCurrentLocaleName(const char *iso_code); int OTTDStringCompare(const char *s1, const char *s2); -bool IsWindowsVistaOrGreater(); #endif /* WIN32_H */ diff --git a/src/sound/win32_s.cpp b/src/sound/win32_s.cpp index eccbb4f42a..87959e5860 100644 --- a/src/sound/win32_s.cpp +++ b/src/sound/win32_s.cpp @@ -17,6 +17,7 @@ #include "win32_s.h" #include #include +#include #include "../os/windows/win32.h" #include "../thread.h" @@ -69,7 +70,7 @@ const char *SoundDriver_Win32::Start(const StringList &parm) wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; /* Limit buffer size to prevent overflows. */ - _bufsize = GetDriverParamInt(parm, "bufsize", (GB(GetVersion(), 0, 8) > 5) ? 8192 : 4096); + _bufsize = GetDriverParamInt(parm, "bufsize", IsWindowsVistaOrGreater() ? 8192 : 4096); _bufsize = std::min(_bufsize, UINT16_MAX); try { diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp index ad7514476b..fc78a30921 100644 --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -35,7 +35,7 @@ static bool WarnCorruptSprite(const SpriteFile &file, size_t file_pos, int line) { static byte warning_level = 0; if (warning_level == 0) { - SetDParamStr(0, file.GetSimplifiedFilename().c_str()); + SetDParamStr(0, file.GetSimplifiedFilename()); ShowErrorMessage(STR_NEWGRF_ERROR_CORRUPT_SPRITE, INVALID_STRING_ID, WL_ERROR); } DEBUG(sprite, warning_level, "[%i] Loading corrupted sprite from %s at position %i", line, file.GetSimplifiedFilename().c_str(), (int)file_pos); diff --git a/src/string.cpp b/src/string.cpp index 30d4c02588..350d6ec7ae 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -390,6 +390,33 @@ void StrTrimInPlace(std::string &str) StrRightTrimInPlace(str); } +/** + * Check whether the given string starts with the given prefix. + * @param str The string to look at. + * @param prefix The prefix to look for. + * @return True iff the begin of the string is the same as the prefix. + */ +bool StrStartsWith(const std::string_view str, const std::string_view prefix) +{ + size_t prefix_len = prefix.size(); + if (str.size() < prefix_len) return false; + return str.compare(0, prefix_len, prefix, 0, prefix_len) == 0; +} + +/** + * Check whether the given string ends with the given suffix. + * @param str The string to look at. + * @param suffix The suffix to look for. + * @return True iff the end of the string is the same as the suffix. + */ +bool StrEndsWith(const std::string_view str, const std::string_view suffix) +{ + size_t suffix_len = suffix.size(); + if (str.size() < suffix_len) return false; + return str.compare(str.size() - suffix_len, suffix_len, suffix, 0, suffix_len) == 0; +} + + /** Scans the string for colour codes and strips them */ void str_strip_colours(char *str) { diff --git a/src/string_func.h b/src/string_func.h index 8fec9226fb..244eb68cd8 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -56,6 +56,9 @@ bool strtolower(std::string &str, std::string::size_type offs = 0); bool StrValid(const char *str, const char *last) NOACCESS(2); void StrTrimInPlace(std::string &str); +bool StrStartsWith(const std::string_view str, const std::string_view prefix); +bool StrEndsWith(const std::string_view str, const std::string_view suffix); + /** * Check if a string buffer is empty. * diff --git a/src/table/settings/win32_settings.ini b/src/table/settings/win32_settings.ini index e66ab97ee5..d3e233e2a6 100644 --- a/src/table/settings/win32_settings.ini +++ b/src/table/settings/win32_settings.ini @@ -17,8 +17,8 @@ static const SettingTable _win32_settings{ }; #endif /* _WIN32 */ [templates] -SDTG_BOOL = SDTG_BOOL($name, $flags, $var, $def, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $guiproc, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $guiproc, $startup, $extver, nullptr), +SDTG_BOOL = SDTG_BOOL($name, $flags, $var, $def, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $extver, $cat, $guiproc, $startup, nullptr), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $extver, $cat, $guiproc, $startup, nullptr), [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); diff --git a/src/thread.h b/src/thread.h index 55b13ee5d5..d4d341de9e 100644 --- a/src/thread.h +++ b/src/thread.h @@ -17,6 +17,7 @@ #include #if defined(__MINGW32__) #include "3rdparty/mingw-std-threads/mingw.thread.h" +#include "3rdparty/mingw-std-threads/mingw.mutex.h" #endif /** diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 4e75b274b4..2673d9e17b 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -25,6 +25,7 @@ #include "win32_v.h" #include #include +#include #include #include "../safeguards.h" @@ -918,7 +919,7 @@ void VideoDriver_Win32Base::EditBoxLostFocus() SetCandidatePos(this->main_wnd); } -BOOL CALLBACK EnumDisplayMonitorsCallback(HMONITOR hMonitor, HDC hDC, LPRECT rc, LPARAM data) +static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hDC, LPRECT rc, LPARAM data) { auto &list = *reinterpret_cast*>(data); @@ -938,7 +939,7 @@ BOOL CALLBACK EnumDisplayMonitorsCallback(HMONITOR hMonitor, HDC hDC, LPRECT rc, std::vector VideoDriver_Win32Base::GetListOfMonitorRefreshRates() { std::vector rates = {}; - EnumDisplayMonitors(nullptr, nullptr, (MONITORENUMPROC)&EnumDisplayMonitorsCallback, reinterpret_cast(&rates)); + EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, reinterpret_cast(&rates)); return rates; } @@ -1268,6 +1269,12 @@ static void LoadWGLExtensions() if (rc != nullptr) { wglMakeCurrent(dc, rc); +#ifdef __MINGW32__ + /* GCC doesn't understand the expected usage of wglGetProcAddress(). */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif /* __MINGW32__ */ + /* Get list of WGL extensions. */ PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); if (wglGetExtensionsStringARB != nullptr) { @@ -1282,6 +1289,9 @@ static void LoadWGLExtensions() } } +#ifdef __MINGW32__ +#pragma GCC diagnostic pop +#endif wglMakeCurrent(nullptr, nullptr); wglDeleteContext(rc); } diff --git a/src/walltime_func.h b/src/walltime_func.h index 219a8907de..f070d8e2b9 100644 --- a/src/walltime_func.h +++ b/src/walltime_func.h @@ -17,7 +17,7 @@ struct LocalTimeToStruct { static inline std::tm ToTimeStruct(std::time_t time_since_epoch) { std::tm time = {}; -#ifdef WIN32 +#ifdef _WIN32 /* Windows has swapped the parameters around for localtime_s. */ localtime_s(&time, &time_since_epoch); #else @@ -32,7 +32,7 @@ struct UTCTimeToStruct { static inline std::tm ToTimeStruct(std::time_t time_since_epoch) { std::tm time = {}; -#ifdef WIN32 +#ifdef _WIN32 /* Windows has swapped the parameters around for gmtime_s. */ gmtime_s(&time, &time_since_epoch); #else