diff --git a/src/cargotype.h b/src/cargotype.h index 9b0a500f9e..5386d34949 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -185,6 +185,7 @@ private: static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs friend void SetupCargoForClimate(LandscapeID l); + friend void FinaliseCargoArray(); }; extern CargoTypes _cargo_mask; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 173cd16e1a..767759da64 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -3,7 +3,6 @@ add_files( alloc_func.hpp alloc_type.hpp backup_type.hpp - bitmath_func.cpp bitmath_func.hpp checksum_func.hpp container_func.hpp diff --git a/src/core/bitmath_func.cpp b/src/core/bitmath_func.cpp deleted file mode 100644 index ca4abca2bb..0000000000 --- a/src/core/bitmath_func.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file bitmath_func.cpp Functions related to bit mathematics. */ - -#include "../stdafx.h" -#include "bitmath_func.hpp" - -#include "../safeguards.h" - -#ifndef WITH_BITMATH_BUILTINS - -const uint8_t _ffb_64[64] = { - 0, 0, 1, 0, 2, 0, 1, 0, - 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, - 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, - 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, - 3, 0, 1, 0, 2, 0, 1, 0, -}; - -uint8_t FindFirstBit32(uint32_t x) -{ - if (x == 0) return 0; - /* The macro FIND_FIRST_BIT is better to use when your x is - not more than 128. */ - - uint8_t pos = 0; - - if ((x & 0x0000ffff) == 0) { x >>= 16; pos += 16; } - if ((x & 0x000000ff) == 0) { x >>= 8; pos += 8; } - if ((x & 0x0000000f) == 0) { x >>= 4; pos += 4; } - if ((x & 0x00000003) == 0) { x >>= 2; pos += 2; } - if ((x & 0x00000001) == 0) { pos += 1; } - - return pos; -} - -uint8_t FindFirstBit64(uint64_t x) -{ - if (x == 0) return 0; - if ((x & 0x00000000ffffffffULL) != 0) return FindFirstBit32(static_cast(x)); - return FindFirstBit32(static_cast(x >> 32)) + 32; -} - -#endif - -/** - * Search the last set bit in a 64 bit variable. - * - * This algorithm is a static implementation of a log - * congruence search algorithm. It checks the second half - * if there is a bit set search there further. And this - * way further. If no bit is set return 0. - * - * @param x The value to search - * @return The position of the last bit set - */ -uint8_t FindLastBit64(uint64_t x) -{ - if (x == 0) return 0; - - uint8_t pos = 0; - - if ((x & 0xffffffff00000000ULL) != 0) { x >>= 32; pos += 32; } - if ((x & 0x00000000ffff0000ULL) != 0) { x >>= 16; pos += 16; } - if ((x & 0x000000000000ff00ULL) != 0) { x >>= 8; pos += 8; } - if ((x & 0x00000000000000f0ULL) != 0) { x >>= 4; pos += 4; } - if ((x & 0x000000000000000cULL) != 0) { x >>= 2; pos += 2; } - if ((x & 0x0000000000000002ULL) != 0) { pos += 1; } - - return pos; -} diff --git a/src/core/bitmath_func.hpp b/src/core/bitmath_func.hpp index 26dd6dae1c..146d2bd10a 100644 --- a/src/core/bitmath_func.hpp +++ b/src/core/bitmath_func.hpp @@ -10,6 +10,7 @@ #ifndef BITMATH_FUNC_HPP #define BITMATH_FUNC_HPP +#include #include /** @@ -186,110 +187,38 @@ inline T ToggleBit(T &x, const uint8_t y) return x = (T)(x ^ ((T)1U << y)); } -#ifdef WITH_BITMATH_BUILTINS - -#define FIND_FIRST_BIT(x) FindFirstBit(x) - -#else - -/** Lookup table to check which bit is set in a 6 bit variable */ -extern const uint8_t _ffb_64[64]; - /** - * Returns the first non-zero bit in a 6-bit value (from right). + * Search the first set bit in a value. + * When no bit is set, it returns 0. * - * Returns the position of the first bit that is not zero, counted from the - * LSB. Ie, 110100 returns 2, 000001 returns 0, etc. When x == 0 returns - * 0. - * - * @param x The 6-bit value to check the first zero-bit - * @return The first position of a bit started from the LSB or 0 if x is 0. - */ -#define FIND_FIRST_BIT(x) _ffb_64[(x) & 0x3F] - -#endif - -/** - * Search the first set bit in an integer variable. - * - * @param value The value to search - * @return The position of the first bit set, or 0 when value is 0 + * @param x The value to search. + * @return The position of the first bit set. */ template -inline uint8_t FindFirstBit(T value) +constexpr uint8_t FindFirstBit(T x) { - static_assert(sizeof(T) <= sizeof(unsigned long long)); -#ifdef WITH_BITMATH_BUILTINS - if (value == 0) return 0; - typename std::make_unsigned::type unsigned_value = value; - if (sizeof(T) <= sizeof(unsigned int)) { - return __builtin_ctz(unsigned_value); - } else if (sizeof(T) == sizeof(unsigned long)) { - return __builtin_ctzl(unsigned_value); - } else { - return __builtin_ctzll(unsigned_value); - } -#else - if (sizeof(T) <= sizeof(uint32_t)) { - extern uint8_t FindFirstBit32(uint32_t x); - return FindFirstBit32(value); + if (x == 0) return 0; + + if constexpr (std::is_enum_v) { + return std::countr_zero>(x); } else { - extern uint8_t FindFirstBit64(uint64_t x); - return FindFirstBit64(value); + return std::countr_zero(x); } -#endif } /** - * Search the last set bit in an integer variable. + * Search the last set bit in a value. + * When no bit is set, it returns 0. * - * @param value The value to search - * @return The position of the last bit set, or 0 when value is 0 + * @param x The value to search. + * @return The position of the last bit set. */ template -inline uint8_t FindLastBit(T value) +constexpr uint8_t FindLastBit(T x) { - static_assert(sizeof(T) <= sizeof(unsigned long long)); -#ifdef WITH_BITMATH_BUILTINS - if (value == 0) return 0; - typename std::make_unsigned::type unsigned_value = value; - if (sizeof(T) <= sizeof(unsigned int)) { - return __builtin_clz(1) - __builtin_clz(unsigned_value); - } else if (sizeof(T) == sizeof(unsigned long)) { - return __builtin_clzl(1) - __builtin_clzl(unsigned_value); - } else { - return __builtin_clzll(1) - __builtin_clzll(unsigned_value); - } -#else - extern uint8_t FindLastBit64(uint64_t x); - return FindLastBit64(value); -#endif -} + if (x == 0) return 0; - -/** - * Finds the position of the first non-zero bit in an integer. - * - * This function returns the position of the first bit set in the - * integer. It does only check the bits of the bitmask - * 0x3F3F (0011111100111111). - * - * @param value The value to check the first bits - * @return The position of the first bit which is set - * @see FIND_FIRST_BIT - */ -inline uint8_t FindFirstBit2x64(const int value) -{ -#ifdef WITH_BITMATH_BUILTINS - return FindFirstBit(value & 0x3F3F); -#else - if (value == 0) return 0; - if ((value & 0x3F) == 0) { - return FIND_FIRST_BIT((value >> 8) & 0x3F) + 8; - } else { - return FIND_FIRST_BIT(value & 0x3F); - } -#endif + return std::countl_zero(1) - std::countl_zero(x); } /** @@ -315,32 +244,13 @@ inline T KillFirstBit(T value) * @return the number of bits. */ template -inline uint CountBits(T value) +constexpr uint CountBits(T value) { - static_assert(sizeof(T) <= sizeof(unsigned long long)); -#ifdef WITH_BITMATH_BUILTINS - typename std::make_unsigned::type unsigned_value = value; - if (sizeof(T) <= sizeof(unsigned int)) { - return __builtin_popcount(unsigned_value); - } else if (sizeof(T) == sizeof(unsigned long)) { - return __builtin_popcountl(unsigned_value); + if constexpr (std::is_enum_v) { + return std::popcount>(value); } else { - return __builtin_popcountll(unsigned_value); - } -#else - uint num; - - /* This loop is only called once for every bit set by clearing the lowest - * bit in each loop. The number of bits is therefore equal to the number of - * times the loop was called. It was found at the following website: - * http://graphics.stanford.edu/~seander/bithacks.html */ - - for (num = 0; value != 0; num++) { - value &= (T)(value - 1); + return std::popcount(value); } - - return num; -#endif } /** @@ -353,8 +263,8 @@ template inline bool IsOddParity(T value) { static_assert(sizeof(T) <= sizeof(unsigned long long)); -#ifdef WITH_BITMATH_BUILTINS typename std::make_unsigned::type unsigned_value = value; +#ifdef WITH_BITMATH_BUILTINS if (sizeof(T) <= sizeof(unsigned int)) { return __builtin_parity(unsigned_value); } else if (sizeof(T) == sizeof(unsigned long)) { @@ -363,7 +273,7 @@ inline bool IsOddParity(T value) return __builtin_parityll(unsigned_value); } #else - return CountBits(value) & 1; + return CountBits(unsigned_value) & 1; #endif } diff --git a/src/core/endian_func.hpp b/src/core/endian_func.hpp index 1b236c8cce..2f2ac21d56 100644 --- a/src/core/endian_func.hpp +++ b/src/core/endian_func.hpp @@ -46,18 +46,4 @@ #define TO_LE64(x) (x) #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ -inline uint16_t ReadLE16Aligned(const void *x) -{ - return FROM_LE16(*(const uint16_t*)x); -} - -inline uint16_t ReadLE16Unaligned(const void *x) -{ -#if OTTD_ALIGNMENT == 1 - return ((const byte*)x)[0] | ((const byte*)x)[1] << 8; -#else - return FROM_LE16(*(const uint16_t*)x); -#endif /* OTTD_ALIGNMENT == 1 */ -} - #endif /* ENDIAN_FUNC_HPP */ diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp index 28ea1f00f3..f3aa4b705d 100644 --- a/src/core/geometry_type.hpp +++ b/src/core/geometry_type.hpp @@ -22,6 +22,9 @@ struct Point { int x; int y; + constexpr Point() : x(0), y(0) {} + constexpr Point(int x, int y) : x(x), y(y) {} + bool operator==(const Point&) const = default; }; diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 9bd9003d73..21002efd5a 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -290,9 +290,15 @@ static void ExtractStringParams(const StringData &data, StringParamsList ¶ms StringParams ¶m = params.emplace_back(); ParsedCommandStruct pcs = ExtractCommandString(ls->english.c_str(), false); - for (const CmdStruct *cs : pcs.consuming_commands) { - if (cs == nullptr) break; - param.emplace_back(GetParamType(cs), cs->consumes); + for (auto it = pcs.consuming_commands.begin(); it != pcs.consuming_commands.end(); it++) { + if (*it == nullptr) { + /* Skip empty param unless a non empty param exist after it. */ + if (std::all_of(it, pcs.consuming_commands.end(), [](auto cs) { return cs == nullptr; })) break; + param.emplace_back(StringParam::UNUSED, 1, nullptr); + continue; + } + const CmdStruct *cs = *it; + param.emplace_back(GetParamType(cs), cs->consumes, cs->cmd); } } } diff --git a/src/game/game_text.hpp b/src/game/game_text.hpp index 5fceecb593..bfda48330c 100644 --- a/src/game/game_text.hpp +++ b/src/game/game_text.hpp @@ -12,6 +12,7 @@ struct StringParam { enum ParamType : uint8_t { + UNUSED, RAW_STRING, STRING, OTHER @@ -19,8 +20,9 @@ struct StringParam { ParamType type; uint8_t consumes; + const char *cmd; - StringParam(ParamType type, uint8_t consumes) : type(type), consumes(consumes) {} + StringParam(ParamType type, uint8_t consumes, const char *cmd) : type(type), consumes(consumes), cmd(cmd) {} }; using StringParams = std::vector; using StringParamsList = std::vector; diff --git a/src/gfx.cpp b/src/gfx.cpp index 5fcb0d86b9..fb3e3c5adc 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -620,9 +620,9 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, /* Not a valid glyph (empty) */ if (glyph == 0xFFFF) continue; - int begin_x = (int)positions[i * 2] + left - offset_x; - int end_x = (int)positions[i * 2 + 2] + left - offset_x - 1; - int top = (int)positions[i * 2 + 1] + y; + int begin_x = positions[i].x + left - offset_x; + int end_x = positions[i + 1].x + left - offset_x - 1; + int top = positions[i].y + y; /* Truncated away. */ if (truncation && (begin_x < min_x || end_x > max_x)) continue; diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index b6f7519efe..1d662d7b77 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -263,8 +263,7 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const for (int i = 0; i < run.GetGlyphCount(); i++) { /* Matching glyph? Return position. */ if ((size_t)charmap[i] == index) { - Point p = { (int)positions[i * 2], (int)positions[i * 2 + 1] }; - return p; + return positions[i]; } } } @@ -295,8 +294,8 @@ ptrdiff_t Layouter::GetCharAtPosition(int x, size_t line_index) const /* Not a valid glyph (empty). */ if (glyphs[i] == 0xFFFF) continue; - int begin_x = (int)positions[i * 2]; - int end_x = (int)positions[i * 2 + 2]; + int begin_x = positions[i].x; + int end_x = positions[i + 1].x; if (IsInsideMM(x, begin_x, end_x)) { /* Found our glyph, now convert to UTF-8 string index. */ diff --git a/src/gfx_layout.h b/src/gfx_layout.h index fff14c8f0f..d8052c77e0 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -100,10 +100,10 @@ public: virtual ~VisualRun() = default; virtual const Font *GetFont() const = 0; virtual int GetGlyphCount() const = 0; - virtual const GlyphID *GetGlyphs() const = 0; - virtual const float *GetPositions() const = 0; + virtual const std::vector &GetGlyphs() const = 0; + virtual const std::vector &GetPositions() const = 0; virtual int GetLeading() const = 0; - virtual const int *GetGlyphToCharMap() const = 0; + virtual const std::vector &GetGlyphToCharMap() const = 0; }; /** A single line worth of VisualRuns. */ diff --git a/src/gfx_layout_fallback.cpp b/src/gfx_layout_fallback.cpp index 39c6efab76..be27383668 100644 --- a/src/gfx_layout_fallback.cpp +++ b/src/gfx_layout_fallback.cpp @@ -40,7 +40,7 @@ public: /** Visual run contains data about the bit of text with the same font. */ class FallbackVisualRun : public ParagraphLayouter::VisualRun { std::vector glyphs; ///< The glyphs we're drawing. - std::vector positions; ///< The positions of the glyphs. + std::vector positions; ///< The positions of the glyphs. std::vector glyph_to_char; ///< The char index of the glyphs. Font *font; ///< The font used to layout these. @@ -49,10 +49,10 @@ public: FallbackVisualRun(Font *font, const char32_t *chars, int glyph_count, int char_offset, int x); const Font *GetFont() const override { return this->font; } int GetGlyphCount() const override { return static_cast(this->glyphs.size()); } - const GlyphID *GetGlyphs() const override { return this->glyphs.data(); } - const float *GetPositions() const override { return this->positions.data(); } + const std::vector &GetGlyphs() const override { return this->glyphs; } + const std::vector &GetPositions() const override { return this->positions; } int GetLeading() const override { return this->GetFont()->fc->GetHeight(); } - const int *GetGlyphToCharMap() const override { return this->glyph_to_char.data(); } + const std::vector &GetGlyphToCharMap() const override { return this->glyph_to_char; } }; /** A single line worth of VisualRuns. */ @@ -118,21 +118,23 @@ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const this->glyph_to_char.reserve(char_count); /* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */ - this->positions.resize(char_count * 2 + 2); - this->positions[0] = x; + this->positions.reserve(char_count + 1); + int advance = x; for (int i = 0; i < char_count; i++) { const GlyphID &glyph_id = this->glyphs.emplace_back(font->fc->MapCharToGlyph(chars[i])); if (isbuiltin) { - this->positions[2 * i + 1] = font->fc->GetAscender(); // Apply sprite font's ascender. + this->positions.emplace_back(advance, font->fc->GetAscender()); // Apply sprite font's ascender. } else if (chars[i] >= SCC_SPRITE_START && chars[i] <= SCC_SPRITE_END) { - this->positions[2 * i + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre + this->positions.emplace_back(advance, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre } else { - this->positions[2 * i + 1] = 0; // No ascender adjustment. + this->positions.emplace_back(advance, 0); // No ascender adjustment. } - this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(glyph_id); + advance += font->fc->GetGlyphWidth(glyph_id); this->glyph_to_char.push_back(char_offset + i); } + /* End-of-run position. */ + this->positions.emplace_back(advance, 0); } /** @@ -163,7 +165,7 @@ int FallbackParagraphLayout::FallbackLine::GetWidth() const * the last run gives us the end of the line and thus the width. */ const auto &run = this->GetVisualRun(this->CountRuns() - 1); - return (int)run.GetPositions()[run.GetGlyphCount() * 2]; + return run.GetPositions().back().x; } /** diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index e5554ff378..982a89a0d6 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -45,7 +45,7 @@ public: std::vector glyphs; ///< The glyphs of the run. Valid after Shape() is called. std::vector advance; ///< The advance (width) of the glyphs. Valid after Shape() is called. std::vector glyph_to_char; ///< The mapping from glyphs to characters. Valid after Shape() is called. - std::vector positions; ///< The positions of the glyphs. Valid after Shape() is called. + std::vector positions; ///< The positions of the glyphs. Valid after Shape() is called. int total_advance = 0; ///< The total advance of the run. Valid after Shape() is called. ICURun(int start, int length, UBiDiLevel level, UScriptCode script = USCRIPT_UNKNOWN, Font *font = nullptr) : start(start), length(length), level(level), script(script), font(font) {} @@ -62,7 +62,7 @@ public: class ICUVisualRun : public ParagraphLayouter::VisualRun { private: std::vector glyphs; - std::vector positions; + std::vector positions; std::vector glyph_to_char; int total_advance; @@ -71,9 +71,9 @@ public: public: ICUVisualRun(const ICURun &run, int x); - const GlyphID *GetGlyphs() const override { return this->glyphs.data(); } - const float *GetPositions() const override { return this->positions.data(); } - const int *GetGlyphToCharMap() const override { return this->glyph_to_char.data(); } + const std::vector &GetGlyphs() const override { return this->glyphs; } + const std::vector &GetPositions() const override { return this->positions; } + const std::vector &GetGlyphToCharMap() const override { return this->glyph_to_char; } const Font *GetFont() const override { return this->font; } int GetLeading() const override { return this->font->fc->GetHeight(); } @@ -135,16 +135,9 @@ ICUParagraphLayout::ICUVisualRun::ICUVisualRun(const ICURun &run, int x) : assert(!run.positions.empty()); this->positions.reserve(run.positions.size()); - /* "positions" is an array of x/y. So we need to alternate. */ - bool is_x = true; - for (auto &position : run.positions) { - if (is_x) { - this->positions.push_back(position + x); - } else { - this->positions.push_back(position); - } - - is_x = !is_x; + /* Copy positions, moving x coordinate by x offset. */ + for (const Point &pt : run.positions) { + this->positions.emplace_back(pt.x + x, pt.y); } } @@ -186,7 +179,7 @@ void ICURun::Shape(UChar *buff, size_t buff_length) /* Reserve space, as we already know the size. */ this->glyphs.reserve(glyph_count); this->glyph_to_char.reserve(glyph_count); - this->positions.reserve(glyph_count * 2 + 2); + this->positions.reserve(glyph_count + 1); this->advance.reserve(glyph_count); /* Prepare the glyphs/position. ICUVisualRun will give the position an offset if needed. */ @@ -198,13 +191,11 @@ void ICURun::Shape(UChar *buff, size_t buff_length) auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]); this->glyphs.push_back(glyph); - this->positions.push_back(advance); - this->positions.push_back((this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre + this->positions.emplace_back(advance, (this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre x_advance = this->font->fc->GetGlyphWidth(glyph); } else { this->glyphs.push_back(glyph_info[i].codepoint); - this->positions.push_back(glyph_pos[i].x_offset / FONT_SCALE + advance); - this->positions.push_back(glyph_pos[i].y_offset / FONT_SCALE); + this->positions.emplace_back(glyph_pos[i].x_offset / FONT_SCALE + advance, glyph_pos[i].y_offset / FONT_SCALE); x_advance = glyph_pos[i].x_advance / FONT_SCALE; } @@ -213,9 +204,8 @@ void ICURun::Shape(UChar *buff, size_t buff_length) advance += x_advance; } - /* Position has one more element to close off the array. */ - this->positions.push_back(advance); - this->positions.push_back(0); + /* End-of-run position. */ + this->positions.emplace_back(advance, 0); /* Track the total advancement we made. */ this->total_advance = advance; diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 43c25ef552..66ef746320 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -455,7 +455,7 @@ protected: * integer, so at about 31 bits because of the sign bit, the * least significant bits are removed. */ - int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint)); + int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint)); int reduce_range = std::max(mult_range - 31, 0); /* Handle negative values differently (don't shift sign) */ diff --git a/src/house.h b/src/house.h index d7bbd1c93b..0c945da647 100644 --- a/src/house.h +++ b/src/house.h @@ -68,7 +68,7 @@ static_assert(HZB_END == 5); DECLARE_POSTFIX_INCREMENT(HouseZonesBits) -enum HouseZones { ///< Bit Value Meaning +enum HouseZones : uint16_t { ///< Bit Value Meaning HZ_NOZNS = 0x0000, ///< 0 This is just to get rid of zeros, meaning none HZ_ZON1 = 1U << HZB_TOWN_EDGE, ///< 0..4 1,2,4,8,10 which town zones the building can be built in, Zone1 been the further suburb HZ_ZON2 = 1U << HZB_TOWN_OUTSKIRT, diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index aa1fee66c7..be7fe00f4d 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -1045,6 +1045,10 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Marque e STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Escalar chanfros STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Marque esta caixa para dimensionar os chanfros por tamanho de interface +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Usar a fonte "sprite" tradicional +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Marque esta caixa se prefere usar o tipo de fonte tradicional de tamanho fixo. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Fontes anti-alias +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Marque esta caixa para fontes redimensionáveis com anti-alias. STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index 391feed7f3..7d8a1c0275 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -768,7 +768,7 @@ STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLA STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Rute de transport STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Pădure STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Gară -STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Loc încărcare camioane +STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Stația de camioane STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Stație de autobuz STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Aeroport/Heliport STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Port @@ -999,6 +999,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Dolar Hong Kong STR_GAME_OPTIONS_CURRENCY_INR :Rupia Indiană STR_GAME_OPTIONS_CURRENCY_IDR :Rupia indoneziană STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysian +STR_GAME_OPTIONS_CURRENCY_LVL :Lats leton STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Salvare automată STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Alege intervalul de timp dintre salvările automate @@ -1040,6 +1041,10 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Bifați STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scalează marginile STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Bifați această casetă pentru a scala marginile în funcție de dimensiunea interfeței +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Folosiți fontul tradițional al sprite-ului +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Bifați această casetă dacă preferați să utilizați fontul sprite tradițional cu dimensiune fixă. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Fonturi anti-alias +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Bifați această casetă pentru anti-alias fonturi redimensionabile. STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x @@ -1487,7 +1492,7 @@ STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Tip teren: {STRING} -STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Doar TerraGenesis) Frecvența dealurilor din peisaj +STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :Alegeți înălțimea dealurilor și munților din peisaj STR_CONFIG_SETTING_INDUSTRY_DENSITY :Densitatea industriei: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Stabilește câte industrii ar trebui generate și ce nivel ar trebui întreținut pe durata jocului @@ -1496,18 +1501,18 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Distanța maxim STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Rafinăriile de petrol vor fi construite doar la marginea hărții, sau pe coastă, în cazul harților insulare STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Grosimea stratului de zăpadă: {STRING} -STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Controlează înălțimea de la care zăpada apare în peisajul sub-arctic. Zăpada afectează și generarea industriilor și cerințele de creștere a orașelor. Se poate modifica doar prin Editorul de scenarii sau este calculat prin „acoperirea cu zăpadă” +STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Alegeți la ce înălțime începe zăpada în peisajul subarctic. Zăpada afectează, de asemenea, generarea industriei și cerințele de creștere a orașului. Poate fi modificat numai prin Editorul de scenarii sau este calculat în alt mod prin „acoperire cu zăpadă” STR_CONFIG_SETTING_SNOW_COVERAGE :Acoperire cu zăpadă: {STRING} STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :Controlează cantitatea aproximativă de zăpadă în peisajul subarctic. Zăpada afectează și generarea industriilor și cerințele de creștere a orașelor. Se folosește doar la generarea hărții. Terenul apropiat de nivelul mării este întotdeauna fără zăpadă STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_DESERT_COVERAGE :Acoperire cu deșert: {STRING} -STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Controlează întinderea aproximativă de deșert din peisajul tropical. Deșert afectează și generarea industriilor. Parametrul se folosește doar la generarea hărții +STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Controlează întinderea aproximativă de deșert din peisajul tropical. Deșertul afectează și generarea industriilor. Parametrul se folosește doar la generarea hărții STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Duritatea terenului (doar pt TerraGenesis) : {STRING} -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Doar TerraGenesis) Alegeți frecvența dealurilor: Peisajele line au dealuri mai puține și mai întinse. Peisajele dure au multe dealuri și pot arăta repetitiv +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :Alegeți forma și numărul de dealuri. Peisajele netede au mai puține dealuri, dealuri mai largi, în timp ce peisajele accidentate au dealuri mai multe dar mai mici. ###length 4 STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Foarte fin STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Fin @@ -1515,7 +1520,7 @@ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Dur STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Foarte dur STR_CONFIG_SETTING_VARIETY :Distribuția varietății: {STRING} -STR_CONFIG_SETTING_VARIETY_HELPTEXT :(TerraGenesis only) Specifică dacă harta conține și zone muntoase și teren plat. Deoarece aceasta face harta mai plată, alte setări ar trebui să adauge zone muntoase +STR_CONFIG_SETTING_VARIETY_HELPTEXT :Alegeți dacă harta conține atât munți, cât și zone plane. Cu cât varietatea este mai mare, cu atât mai multe diferențe de altitudine între zonele muntoase și cele plate. STR_CONFIG_SETTING_RIVER_AMOUNT :Numărul de râuri: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Alege câte râuri să fie generate @@ -1661,6 +1666,7 @@ STR_CONFIG_SETTING_TIMETABLE_MODE_HELPTEXT :Selectați unit ###length 3 STR_CONFIG_SETTING_TIMETABLE_MODE_DAYS :Zile STR_CONFIG_SETTING_TIMETABLE_MODE_SECONDS :Secunde +STR_CONFIG_SETTING_TIMETABLE_MODE_TICKS :Tick-uri STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Afișează plecările și sosirile din orare: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Arată timpii estimați de plecare și sosire din orar @@ -1772,6 +1778,8 @@ STR_CONFIG_SETTING_SERVINT_DISABLED :Dezactivat STR_CONFIG_SETTING_NOSERVICE :Deactivare service când defecțiunile nu sunt active: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Dacă este activată, vehiculele nu vor întreținute dacă nu se pot defecta +STR_CONFIG_SETTING_STATION_LENGTH_LOADING_PENALTY :Penalizarea vitezei de încărcare pentru trenurile care sunt mai lungi decât gara: {STRING} +STR_CONFIG_SETTING_STATION_LENGTH_LOADING_PENALTY_HELPTEXT :Când este activat, trenurile care sunt prea lungi pentru gară se încarcă mai lent decât un tren care se potrivește cu stația. Această setare nu afectează identificarea traseului. STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Activează limite de viteză pentru vagoane: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Dacă este activată, folosește și limita de viteză a vagoanelor pentru a stabili viteza maximă a trenului @@ -2048,14 +2056,17 @@ STR_CONFIG_SETTING_ACCOUNTING :Contabilitate STR_CONFIG_SETTING_VEHICLES :Vehicule STR_CONFIG_SETTING_VEHICLES_PHYSICS :Fizică STR_CONFIG_SETTING_VEHICLES_ROUTING :Direcționare +STR_CONFIG_SETTING_VEHICLES_ORDERS :Comenzi STR_CONFIG_SETTING_LIMITATIONS :Limitări STR_CONFIG_SETTING_ACCIDENTS :Dezastre / Accidente STR_CONFIG_SETTING_GENWORLD :Generare lume STR_CONFIG_SETTING_ENVIRONMENT :Mediu +STR_CONFIG_SETTING_ENVIRONMENT_TIME :Timp STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :Autorități STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :Orașe STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :Industrii STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :Distribuție cargo +STR_CONFIG_SETTING_ENVIRONMENT_TREES :Copaci STR_CONFIG_SETTING_AI :Concurenți STR_CONFIG_SETTING_AI_NPC :Jucători virtuali STR_CONFIG_SETTING_NETWORK :Rețea @@ -2192,12 +2203,20 @@ STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Arată s STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Arată schemele de culori pentru autovehicule STR_LIVERY_SHIP_TOOLTIP :{BLACK}Arată schemele de culori pentru nave STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Arată schemele de culori pentru aeronave +STR_LIVERY_TRAIN_GROUP_TOOLTIP :{BLACK}Afișați culorile grupurilor de trenuri +STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP :{BLACK}Afișați culorile grupurilor de vehicule rutiere +STR_LIVERY_SHIP_GROUP_TOOLTIP :{BLACK}Afișați culorile grupurilor de nave +STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP :{BLACK}Afișați culorile grupurilor de avioane STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Alege culoarea principală pentru schema selectată. Ctrl+Click va seta această culoare pentru toate schemele STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Alege culoarea secundară pentru schema selectată. Ctrl+Click va seta această culoare pentru toate schemele STR_LIVERY_PANEL_TOOLTIP :{BLACK}Alege o schemă de culori pentru modificare sau mai multe scheme, folosind Ctrl+Click. Apasă pe căsuță pentru a comuta schema +STR_LIVERY_TRAIN_GROUP_EMPTY :Nu sunt create grupuri de trenuri +STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY :Nu sunt create grupuri de vehicule rutiere +STR_LIVERY_SHIP_GROUP_EMPTY :Nu sunt create grupuri de nave +STR_LIVERY_AIRCRAFT_GROUP_EMPTY :Nu sunt create grupuri de avioane ###length 23 -STR_LIVERY_DEFAULT :Uniforma standard +STR_LIVERY_DEFAULT :Vopsire standard STR_LIVERY_STEAM :Locomotivă cu abur STR_LIVERY_DIESEL :Locomotivă diesel STR_LIVERY_ELECTRIC :Locomotivă electrică @@ -2350,7 +2369,7 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Numele j STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Pune parolă STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protejează-ți jocul cu o parolă dacă nu vrei să intre jucători neautorizați -STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Vizibilitate +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Vizibilitate: STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Dacă alți oameni îți pot vedea serverul în lista publică STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} {P client clienți "de clienți"} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Număr maxim de clienți: @@ -2585,7 +2604,7 @@ STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Caută c STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Ești pe cale de a ieși din OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Termenii și condițiile impuse la descărcarea de pe site-uri web externe pot varia:{}Va trebui să accesezi site-urile externe pentru informații referitoare la modul de instalare a conținutului în OpenTTD.{}Dorești să continui? STR_CONTENT_FILTER_TITLE :{BLACK}Filtru nume/etichetă: -STR_CONTENT_OPEN_URL :{BLACK}Vizitează site-ul web +STR_CONTENT_OPEN_URL :{BLACK}Site-ul web STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Vizitează site-ul web al acestei resurse STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Descarcă STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Pornește descărcarea resurselor selectate @@ -2705,9 +2724,9 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Construcție pe STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Construiește o cale ferată. Ctrl comută construirea/eliminarea căii ferate. Shift comută între construire/afișare cost estimat STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Construiește cale ferată în modul automat. Ctrl comută construirea/eliminarea căii ferate. Shift comută între construire/afișare cost estimat STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Construiește un depou feroviar (pentru achiziție și service de trenuri). Shift comută între construire/afișare cost estimat -STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Convertește linia în punct de tranzit. Ctrl permite alipirea punctelor de tranzit distante. Shift comută între convertire/afișare cost estimat +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Construiți un punct de tranzit pe calea ferată. Ctrl permite alăturarea punctelor de tranzit. Shift comută construirea/afișarea estimării costurilor STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Construiește gară. Ctrl permite alipirea stațiilor. Shift comută între construire/afișare cost estimat -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Plasează semnale feroviare. Ctrl comută între semafoare/semnale electrice{}Trage cu mausul pentru a construi automat semnale pe o porțiune de șină dreaptă. Apasă Ctrl pentru a construi semnale până la următoarea joncțiune{}Ctrl+Clic comută deschiderea ferestrei de selecție a tipului de semnal. Shift comută între construire/afișare cost estimat +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Construiți semnal pe calea ferată. Ctrl comută semnalele semafor/luminoase{}Trasarea generează semnale de-a lungul unei porțiuni drepte de șină. Ctrl generează semnale până la următoarea intersecție sau semnal{}Ctrl+Click comută deschiderea ferestrei de selectare a semnalului. Shift comută construirea/afișarea estimării costurilor STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Construiește un pod de cale ferată. Shift comută între construire/afișare cost estimat STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Construiește un tunel feroviar. Shift comută între construire/afișare cost estimat STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Comută construcția/înlăturarea căilor ferate, semnalelor, punctelor de tranzit și a stațiilor. Ctrl+Click înlătură șinele din punctele de tranzit și din stații @@ -2820,7 +2839,7 @@ STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Alege or STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Orientarea stației de autobuz STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Alege orientarea stației de autobuz STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Orientarea platformei pentru camioane -STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Alege orientarea platformei pentru camioane +STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Selectați orientarea stației de camion STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Orientarea stației de tramvai pentru călători STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Alege orientarea stației de tramvai pentru călători STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Orientarea stației de tramvai pentru marfă @@ -2998,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Propriet STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoritatea locală: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Niciuna STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordonate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Data construcției: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit/renovat: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Clasa stației: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tip stație: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Clasă aeroport: {LTBLUE}{STRING} @@ -3064,7 +3083,7 @@ STR_LAI_TREE_NAME_CACTUS_PLANTS :Cactuși STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Gară STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Aeroport -STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Platformă pentru camioane +STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Stația de camioane STR_LAI_STATION_DESCRIPTION_BUS_STATION :Stație de autobuz STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Port STR_LAI_STATION_DESCRIPTION_BUOY :Baliză @@ -3141,7 +3160,7 @@ STR_FRAMERATE_GL_TRAINS :Bilete de tren: STR_FRAMERATE_GL_ROADVEHS :Tifurile vehiculelor rutiere: STR_FRAMERATE_GL_SHIPS :Căpușele navei: STR_FRAMERATE_GL_AIRCRAFT :Tickurile aeronavei: -STR_FRAMERATE_GL_LANDSCAPE :Căpușe mondiale: +STR_FRAMERATE_GL_LANDSCAPE :Tick-urile lumii: STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Decalaj grafic de conexiuni: STR_FRAMERATE_DRAWING :{BLACK}Randare grafică: STR_FRAMERATE_DRAWING_VIEWPORTS :{BLACK} Vizoare globale: @@ -4649,9 +4668,9 @@ STR_AI_DEBUG_MATCH_CASE :{BLACK}Potrivir STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Comută potrivirea pe majuscule/minuscule când se compară fișierele log ale AI cu string-ul de oprire STR_AI_DEBUG_CONTINUE :{BLACK}Continuă STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Continuă execuția modulului de Inteligență Artificială -STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Vizualizează datele de debug ale acestui modul de IA +STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Vizualizați rezultatul de debug al acestui AI. Ctrl-Clic pentru a deschide într-o fereastră nouă STR_AI_GAME_SCRIPT :{BLACK}Game Script -STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Verifică log-ul Game Script +STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Verificați jurnalul Scriptului de joc. Ctrl-Clic pentru a deschide într-o fereastră nouă STR_ERROR_AI_NO_AI_FOUND :Nici o IA potrivită a fost găsită{}Această IA este nefuncțională.{}Poți descărca IA-uri folsind opțiunea "Resurse online" din meniul principal. STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}O Inteligentă Artificială/Script Joc s-a oprit în mod eronat. Raportează această problemă autorului împreună cu o captură de ecran a ferestrei Depanare IA/Script Joc @@ -4724,7 +4743,7 @@ STR_TEXTFILE_NAVBACK_TOOLTIP :{BLACK}Reveniț STR_TEXTFILE_NAVFORWARD_TOOLTIP :{BLACK}Reveniți înainte în istoricul navigației STR_TEXTFILE_WRAP_TEXT :{WHITE}Încadrează textul STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Încadrează textul ferestrei ca să fie vizibil integral, fără derulare -STR_TEXTFILE_VIEW_README :{BLACK}Vezi fișierul readme +STR_TEXTFILE_VIEW_README :{BLACK}Vezi fișierul read-me STR_TEXTFILE_VIEW_README_TOOLTIP :Vizualizați "citiți-mă / readme" pentru acest conținut STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Listă modificări STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP :Vizualizați jurnalul de modificări pentru acest conținut diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 7833fc2808..cae88e708a 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -1084,7 +1084,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}有关 STR_BASESET_STATUS :{STRING} {RED}(共有{NUM}份缺失或损坏的文件) -STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}无法撷取可用的屏幕分辨率清单 +STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}检索支持的分辨率列表失败 STR_ERROR_FULLSCREEN_FAILED :{WHITE}无法切换到全屏模式{}尝试使用不同的分辨率 # Custom currency window @@ -1405,7 +1405,7 @@ STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :允许向其他 STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :“打开”时,允许联机游戏模式下公司之间转移资金 STR_CONFIG_SETTING_FREIGHT_TRAINS :货物重量倍数:{STRING} -STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :设置列车所载货物的重量倍数。设定的数值越高,货物对列车而言月中,并影响其加速、转弯及上坡的效率。 +STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :设置列车所载货物的重量倍数。设定的数值越高,货物对列车而言越重,并影响其加速、转弯及上坡的效率。 STR_CONFIG_SETTING_PLANE_SPEED :飞机速度因子:{STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :设置飞机与其它车辆类型的相对速率,使飞机运输收入减少 @@ -1645,9 +1645,9 @@ STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE_YES_EXCEPT_STICKY :是(非粘滞 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :使用 {STRING} 形式的文件名存档 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :游戏存档文件名中日期的格式 ###length 3 -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :完整时间 (2008年12月31日) +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :长格式 (2008 年 12 月 31 日) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :英式时间 (31-12-2008) -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :简短形式 (2008-12-31) +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :国际格式 (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :开始新游戏时自动暂停: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :“打开”时,为了让玩家有时间研究地图,开启新游戏自动暂停游戏 @@ -2858,7 +2858,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}建设 STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}建造船坞(可以购买或保养船只),按住 Shift 键操作可以显示所需资金 STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}建造码头。按住 Ctrl 键允许合并站台,按住 Shift 键操作可以显示所需资金 STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}放置一个浮标,该浮标可以用作路点,按住 Shift 键操作可以显示所需资金 -STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}建设水渠,按住 Shift 键操作可以显示所需资金 +STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}建设渡槽,按住 Shift 键操作可以显示所需资金 STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}修建运河{}当地形处于海平面时{}按住 Ctrl键 可以定义水域 STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}放置河流。按住Ctrl键选择对角线区域 @@ -3025,9 +3025,9 @@ STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}坐标 STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}建造/翻新于:{LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}车站分类: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}车站类型: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}飞机场分类: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}飞机场名字: {LTBLUE}{STRING} -STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}机场区域名称: {LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}机场等级:{LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}机场名称:{LTBLUE}{STRING} +STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}机场区域名称:{LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}接受货物:{LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) @@ -3605,7 +3605,7 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{PUSH_COLOUR}{Y STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{PUSH_COLOUR}{YELLOW}进行大型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务。{}为位于该城镇中心较远距离内的车站提供暂时的评分增益。{}{POP_COLOUR}费用:{CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{PUSH_COLOUR}{YELLOW}资助市政道路进行重建。{}将造成市内交通阻断 6 个月。{}{POP_COLOUR}费用:{CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{PUSH_COLOUR}{YELLOW}以公司的名义设立一尊塑像。{}为位于该城镇的车站提供永久的评分增益。{}{POP_COLOUR}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{PUSH_COLOUR}{YELLOW}资助市内建设新的商业设施。{}为城镇提供暂时的成长速度增益。{}{POP_COLOUR}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{PUSH_COLOUR}{YELLOW}资助市内建设新的房屋建筑。{}为城镇提供暂时的成长速度增益。{}{POP_COLOUR}费用:{CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{PUSH_COLOUR}{YELLOW}购买该市一年的运输专营权。{}其间该市的乘客及货物只允许选用贵公司的运输服务。若竞争对手对该市的贿赂成功,此合同将被取消。{}{POP_COLOUR}费用:{CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{PUSH_COLOUR}{YELLOW}贿赂地方政府以提高评价,并终止竞争者的运输专营权,但有被发现后严厉惩罚的风险。{}{POP_COLOUR}费用:{CURRENCY_LONG} @@ -4846,9 +4846,9 @@ STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}必须 STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}无法清除这个区域…… STR_ERROR_SITE_UNSUITABLE :{WHITE}... 地点不合适 STR_ERROR_ALREADY_BUILT :{WHITE}... 已经建好了 -STR_ERROR_OWNED_BY :{WHITE}归 {STRING} 所有 +STR_ERROR_OWNED_BY :{WHITE}……所有者是 {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... 此区域由另一公司所有 -STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... 景观数量限制已达上限 +STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}……已达地形限制 STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... 已达地块清理限制 STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... 已经达最大植树量 STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}名称重复!请重新命名. @@ -4920,7 +4920,7 @@ STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... 只 STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}由于运气不好,勘探失败了;请再试一次 STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}没有合适的地方勘探这种工业 -STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}没有合适的地方建设 “{STRING}” 工业设施 +STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}没有合适的地方建设 “{STRING}” 工业 STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}请更改参数以生成较好的场景 # Station construction related errors @@ -4933,7 +4933,7 @@ STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}不能 STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}不能在这里兴建机场…… STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}与另一车站相连 -STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}站区太大了…… +STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}……车站范围过大 STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}车站过多 STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}分体站台太多 STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}公共汽车站过多 @@ -4997,7 +4997,7 @@ STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... 含 STR_ERROR_INCOMPATIBLE_RAIL_TYPES :铁路类型不匹配 STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}无法移动载具…… -STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}尾部的列车机车必须和头部的一起协作…… +STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}后端车头一定要跟着前端车头 STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}找不到附近的车库…… STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}在附近找不到车库 @@ -5030,7 +5030,7 @@ STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}不能 # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}必须先拆除公路 -STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... 单行道无法连接路口 +STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... 单行道不能有交叉路口 STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}不能在这里修筑公路…… STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}此处无法建造电车道... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}不能拆除这里的公路…… @@ -5052,7 +5052,7 @@ STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}...不 STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... 不能在运河上建设 STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... 不能在河流上建造…… STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}请先移除运河 -STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}无法在此建设水渠…… +STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}无法在此建设渡槽…… # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}……此处已经有树木了 @@ -5081,13 +5081,13 @@ STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}隧道 STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... 隧道过长 # Object related errors -STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... 对象物太多 +STR_ERROR_TOO_MANY_OBJECTS :{WHITE}……已有太多物件 STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}无法建立物件... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}目标处有其他物体 STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}目标处有公司总部 STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}不能购买这个地块! STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}你已经拥有此地块! -STR_ERROR_BUILD_OBJECT_LIMIT_REACHED :{WHITE}...对象构造达到极限 +STR_ERROR_BUILD_OBJECT_LIMIT_REACHED :{WHITE}……已达物件建造上限 # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}无法新建分组…… @@ -5109,7 +5109,7 @@ STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}指定 ###length VEHICLE_TYPES STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}列车不可用 -STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}车辆不可用 +STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}载具已经停产 STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}船只不可用 STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}飞机不可用 @@ -5203,7 +5203,7 @@ STR_ERROR_NO_BUS_STATION :{WHITE}没有 STR_ERROR_NO_TRUCK_STATION :{WHITE}没有货车站 STR_ERROR_NO_DOCK :{WHITE}这里没有码头 STR_ERROR_NO_AIRPORT :{WHITE}没有机场/直升机场 -STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}没有兼容此道路类型的站点 +STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}没有兼容载具对应道路类型的站点 STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE :{WHITE}没有兼容此有轨电车道路类型的站点 STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}没有适合铰接式道路车辆的站点.{}铰接式道路车辆需要通过式车站,而不是港湾式车站 STR_ERROR_AIRPORT_NO_PLANES :{WHITE}这架飞机不能降落在这个直升机场 @@ -5213,7 +5213,7 @@ STR_ERROR_NO_BUOY :{WHITE}没有 # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}不能给车辆编制时刻表… -STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}车辆只能在站内等候。 +STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}载具只能在车站停靠等候 STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}此车辆将不停靠本站。 STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... 时刻表不完整 STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}……时刻表尚未开始 @@ -5629,7 +5629,7 @@ STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut 直 ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{ZEROFILL_NUM}-{ZEROFILL_NUM}-{NUM} -STR_FORMAT_DATE_SHORT :{STRING} {NUM} +STR_FORMAT_DATE_SHORT :{1:NUM} {0:STRING} STR_FORMAT_DATE_LONG :{2:NUM} 年 {1:STRING} 月 {0:STRING} 日 STR_FORMAT_DATE_ISO :{2:NUM}-{1:ZEROFILL_NUM}-{0:ZEROFILL_NUM} diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index 18e5b706d3..68de8484f8 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -651,6 +651,9 @@ static void MidiThreadProc() TransmitNotesOff(_buffer, block_time, cur_time); MemSetT(channel_volumes, 127, lengthof(channel_volumes)); + /* Invalidate current volume. */ + current_volume = UINT8_MAX; + last_volume_time = 0; /* Take the current time plus the preload time as the music start time. */ clock->GetTime(&playback_start_time); diff --git a/src/music/win32_m.cpp b/src/music/win32_m.cpp index 24120890b6..69301bcaf3 100644 --- a/src/music/win32_m.cpp +++ b/src/music/win32_m.cpp @@ -110,6 +110,8 @@ static void TransmitStandardSysex(MidiSysexMessage msg) */ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR) { + static int volume_throttle = 0; + /* Ensure only one timer callback is running at once, and prevent races on status flags */ std::unique_lock mutex_lock(_midi.lock, std::defer_lock); if (!mutex_lock.try_lock()) return; @@ -163,6 +165,9 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR _midi.current_block = 0; MemSetT(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes)); + /* Invalidate current volume. */ + _midi.current_volume = UINT8_MAX; + volume_throttle = 0; } } else if (!_midi.playing) { /* not playing, stop the timer */ @@ -173,7 +178,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR } /* check for volume change */ - static int volume_throttle = 0; if (_midi.current_volume != _midi.new_volume) { if (volume_throttle == 0) { DEBUG(driver, 2, "Win32-MIDI: timer: volume change"); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 18a464e3c9..c18553a46c 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -10825,13 +10825,13 @@ static void FinaliseEngineArray() } /** Check for invalid cargoes */ -static void FinaliseCargoArray() +void FinaliseCargoArray() { - for (CargoSpec *cs : CargoSpec::Iterate()) { - if (!cs->IsValid()) { - cs->name = cs->name_single = cs->units_volume = STR_NEWGRF_INVALID_CARGO; - cs->quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY; - cs->abbrev = STR_NEWGRF_INVALID_CARGO_ABBREV; + for (CargoSpec &cs : CargoSpec::array) { + if (!cs.IsValid()) { + cs.name = cs.name_single = cs.units_volume = STR_NEWGRF_INVALID_CARGO; + cs.quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY; + cs.abbrev = STR_NEWGRF_INVALID_CARGO_ABBREV; } } } diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 9470696677..d61410b5ed 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -461,7 +461,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, Ho case 0x41: return 0; /* Town zone */ - case 0x42: return FIND_FIRST_BIT(HouseSpec::Get(this->house_id)->building_availability & HZ_ZONALL); // first available + case 0x42: return FindFirstBit(HouseSpec::Get(this->house_id)->building_availability & HZ_ZONALL); // first available /* Terrain type */ case 0x43: return _settings_game.game_creation.landscape == LT_ARCTIC && (HouseSpec::Get(house_id)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW)) == HZ_SUBARTC_ABOVE ? 4 : 0; diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index 2426e6fd18..3049da91b3 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -73,7 +73,7 @@ public: class CoreTextVisualRun : public ParagraphLayouter::VisualRun { private: std::vector glyphs; - std::vector positions; + std::vector positions; std::vector glyph_to_char; int total_advance = 0; @@ -83,9 +83,9 @@ public: CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff); CoreTextVisualRun(CoreTextVisualRun &&other) = default; - const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; } - const float *GetPositions() const override { return &this->positions[0]; } - const int *GetGlyphToCharMap() const override { return &this->glyph_to_char[0]; } + const std::vector &GetGlyphs() const override { return this->glyphs; } + const std::vector &GetPositions() const override { return this->positions; } + const std::vector &GetGlyphToCharMap() const override { return this->glyph_to_char; } const Font *GetFont() const override { return this->font; } int GetLeading() const override { return this->font->fc->GetHeight(); } @@ -242,7 +242,7 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font CGPoint pts[this->glyphs.size()]; CTRunGetPositions(run, CFRangeMake(0, 0), pts); - this->positions.resize(this->glyphs.size() * 2 + 2); + this->positions.reserve(this->glyphs.size() + 1); /* Convert glyph array to our data type. At the same time, substitute * the proper glyphs for our private sprite glyphs. */ @@ -252,16 +252,15 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END && (gl[i] == 0 || gl[i] == 3)) { /* A glyph of 0 indidicates not found, while apparently 3 is what char 0xFFFC maps to. */ this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]); - this->positions[i * 2 + 0] = pts[i].x; - this->positions[i * 2 + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre + this->positions.emplace_back(pts[i].x, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre } else { this->glyphs[i] = gl[i]; - this->positions[i * 2 + 0] = pts[i].x; - this->positions[i * 2 + 1] = pts[i].y; + this->positions.emplace_back(pts[i].x, pts[i].y); } } this->total_advance = (int)std::ceil(CTRunGetTypographicBounds(run, CFRangeMake(0, 0), nullptr, nullptr, nullptr)); - this->positions[this->glyphs.size() * 2] = this->positions[0] + this->total_advance; + /* End-of-run position. */ + this->positions.emplace_back(this->positions.front().x + this->total_advance, 0); } /** diff --git a/src/os/unix/font_unix.cpp b/src/os/unix/font_unix.cpp index 72745e92e4..69fd218450 100644 --- a/src/os/unix/font_unix.cpp +++ b/src/os/unix/font_unix.cpp @@ -34,6 +34,8 @@ static std::tuple SplitFontFamilyAndStyle(std::string_ if (separator == std::string_view::npos) return { std::string(font_name), std::string() }; auto begin = font_name.find_first_not_of("\t ", separator + 1); + if (begin == std::string_view::npos) return { std::string(font_name.substr(0, separator)), std::string() }; + return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) }; } diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index 63da9c0bab..ee6210e503 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -75,7 +75,7 @@ public: class UniscribeVisualRun : public ParagraphLayouter::VisualRun { private: std::vector glyphs; - std::vector positions; + std::vector positions; std::vector char_to_glyph; int start_pos; @@ -83,19 +83,15 @@ public: int num_glyphs; Font *font; - mutable int *glyph_to_char = nullptr; + mutable std::vector glyph_to_char; public: UniscribeVisualRun(const UniscribeRun &range, int x); UniscribeVisualRun(UniscribeVisualRun &&other) noexcept; - ~UniscribeVisualRun() override - { - free(this->glyph_to_char); - } - const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; } - const float *GetPositions() const override { return &this->positions[0]; } - const int *GetGlyphToCharMap() const override; + const std::vector &GetGlyphs() const override { return this->glyphs; } + const std::vector &GetPositions() const override { return this->positions; } + const std::vector &GetGlyphToCharMap() const override; const Font *GetFont() const override { return this->font; } int GetLeading() const override { return this->font->fc->GetHeight(); } @@ -481,30 +477,29 @@ int UniscribeParagraphLayout::UniscribeLine::GetWidth() const UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(const UniscribeRun &range, int x) : glyphs(range.ft_glyphs), char_to_glyph(range.char_to_glyph), start_pos(range.pos), total_advance(range.total_advance), font(range.font) { this->num_glyphs = (int)glyphs.size(); - this->positions.resize(this->num_glyphs * 2 + 2); + this->positions.reserve(this->num_glyphs + 1); - int advance = 0; + int advance = x; for (int i = 0; i < this->num_glyphs; i++) { - this->positions[i * 2 + 0] = range.offsets[i].du + advance + x; - this->positions[i * 2 + 1] = range.offsets[i].dv; + this->positions.emplace_back(range.offsets[i].du + advance, range.offsets[i].dv); advance += range.advances[i]; } - this->positions[this->num_glyphs * 2] = advance + x; + /* End-of-run position. */ + this->positions.emplace_back(advance, 0); } UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(UniscribeVisualRun&& other) noexcept : glyphs(std::move(other.glyphs)), positions(std::move(other.positions)), char_to_glyph(std::move(other.char_to_glyph)), - start_pos(other.start_pos), total_advance(other.total_advance), num_glyphs(other.num_glyphs), font(other.font) + start_pos(other.start_pos), total_advance(other.total_advance), num_glyphs(other.num_glyphs), font(other.font), + glyph_to_char(std::move(other.glyph_to_char)) { - this->glyph_to_char = other.glyph_to_char; - other.glyph_to_char = nullptr; } -const int *UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const +const std::vector &UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const { - if (this->glyph_to_char == nullptr) { - this->glyph_to_char = CallocT(this->GetGlyphCount()); + if (this->glyph_to_char.empty()) { + this->glyph_to_char.resize(this->GetGlyphCount()); /* The char to glyph array contains the first glyph index of the cluster that is associated * with each character. It is possible for a cluster to be formed of several chars. */ diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index dce96415bb..2d5e3db90d 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -1223,11 +1223,11 @@ bool NPFShipCheckReverse(const Ship *v, Trackdir *best_td) if (best_td != nullptr) { DiagDirection entry = ReverseDiagDir(VehicleExitDir(v->direction, v->state)); TrackdirBits rtds = DiagdirReachesTrackdirs(entry) & GetTileTrackdirBits(v->tile, TRANSPORT_WATER, 0, entry); - Trackdir best = (Trackdir)FindFirstBit2x64(rtds); + Trackdir best = (Trackdir)FindFirstBit(rtds); rtds = KillFirstBit(rtds); if (rtds == TRACKDIR_BIT_NONE) return false; /* At most one choice. */ for (; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) { - Trackdir td = (Trackdir)FindFirstBit2x64(rtds); + Trackdir td = (Trackdir)FindFirstBit(rtds); ftd = NPFRouteToStationOrTileTwoWay(v->tile, best, false, v->tile, td, false, &fstd, &user); if (ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) best = td; } diff --git a/src/pathfinder/yapf/yapf_base.hpp b/src/pathfinder/yapf/yapf_base.hpp index dce0af92d5..d8273891df 100644 --- a/src/pathfinder/yapf/yapf_base.hpp +++ b/src/pathfinder/yapf/yapf_base.hpp @@ -193,7 +193,7 @@ public: { bool is_choice = (KillFirstBit(tf.m_new_td_bits) != TRACKDIR_BIT_NONE); for (TrackdirBits rtds = tf.m_new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) { - Trackdir td = (Trackdir)FindFirstBit2x64(rtds); + Trackdir td = (Trackdir)FindFirstBit(rtds); Node &n = Yapf().CreateNewNode(); n.Set(parent, tf.m_new_tile, td, is_choice); node_func(n); diff --git a/src/pathfinder/yapf/yapf_common.hpp b/src/pathfinder/yapf/yapf_common.hpp index 1a08b9a6b2..a154429bd5 100644 --- a/src/pathfinder/yapf/yapf_common.hpp +++ b/src/pathfinder/yapf/yapf_common.hpp @@ -44,7 +44,7 @@ public: { bool is_choice = (KillFirstBit(m_orgTrackdirs) != TRACKDIR_BIT_NONE); for (TrackdirBits tdb = m_orgTrackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) { - Trackdir td = (Trackdir)FindFirstBit2x64(tdb); + Trackdir td = (Trackdir)FindFirstBit(tdb); Node &n1 = Yapf().CreateNewNode(); n1.Set(nullptr, m_orgTile, td, is_choice); Yapf().AddStartupNode(n1); diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index c92bff0402..f8a9f0fd97 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -754,7 +754,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th } /* Gather the next tile/trackdir/tile_type/rail_type. */ - TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit2x64(tf_local.m_new_td_bits)); + TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit(tf_local.m_new_td_bits)); if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, MP_RAILWAY)) { if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) { diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp index cd867b1859..5d0f222f45 100644 --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -189,7 +189,7 @@ public: /* if there are more trackdirs available & reachable, we are at the end of segment */ if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break; - Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits); + Trackdir new_td = (Trackdir)FindFirstBit(F.m_new_td_bits); /* stop if RV is on simple loop with no junctions */ if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false; @@ -638,7 +638,7 @@ Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDi } Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found, path_cache); - return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs); + return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit(trackdirs); } FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance) diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index 2f20164f26..d229f2d79a 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -206,7 +206,7 @@ public: /* use vehicle's current direction if that's possible, otherwise use first usable one. */ Trackdir veh_dir = v->GetVehicleTrackdir(); - return (HasTrackdir(trackdirs, veh_dir)) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs); + return (HasTrackdir(trackdirs, veh_dir)) ? veh_dir : (Trackdir)FindFirstBit(trackdirs); } /* Move back to the old tile/trackdir (where ship is coming from). */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 9cc292d803..604ac09c3f 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1172,7 +1172,7 @@ bool FloodHalftile(TileIndex t) TrackBits to_remove = lower_track & rail_bits; if (to_remove != 0) { Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); - flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded(); + flooded = DoCommand(t, 0, FindFirstBit(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded(); cur_company.Restore(); if (!flooded) return flooded; // not yet floodable rail_bits = rail_bits & ~to_remove; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index fb31609d6d..6f3519eca4 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -224,7 +224,7 @@ static DiagDirection OneWaySideJunctionRoadRoadBitsToDiagDir(RoadBits bits) * ROAD_NW (bit 0) -> DIAGDIR_SW (2) * ROAD_NE (bit 3) -> DIAGDIR_NW (3) */ - uint8_t bit = FIND_FIRST_BIT(bits ^ ROAD_ALL); + uint8_t bit = FindFirstBit(bits ^ ROAD_ALL); bit ^= 3; return (DiagDirection)((bit + 3 + (_settings_game.vehicle.road_side * 2)) % 4); } @@ -332,7 +332,7 @@ static InterpolateRoadResult InterpolateRoadFollowRoadBit(TileIndex tile, uint8_ RoadBits remaining = rb & ~incoming; if (!HasExactlyOneBit(remaining)) return IRR_NONE; tile = next; - bit = FIND_FIRST_BIT(remaining); + bit = FindFirstBit(remaining); } while (tile != start); return IRR_NONE; } @@ -344,7 +344,7 @@ static void InterpolateRoadFollowRoadBitSetState(TileIndex tile, uint8_t bit, In if (irr == IRR_NONE) { SetRoadCachedOneWayState(tile, RCOWS_NORMAL); } else { - uint8_t inbit = FIND_FIRST_BIT(GetAnyRoadBits(tile, RTT_ROAD, true) & ~(1 << bit)); + uint8_t inbit = FindFirstBit(GetAnyRoadBits(tile, RTT_ROAD, true) & ~static_cast(1 << bit)); /* inbit bit piece Outgoing Trackdir IRR_IN case * * 0 1 ROAD_W TRACKDIR_LEFT_S RCOWS_NON_JUNCTION_A @@ -382,7 +382,7 @@ static void InterpolateRoadFollowRoadBitSetState(TileIndex tile, uint8_t bit, In RoadBits remaining = rb & ~incoming; if (!HasExactlyOneBit(remaining)) return; tile = next; - bit = FIND_FIRST_BIT(remaining); + bit = FindFirstBit(remaining); } while (tile != start); } @@ -396,8 +396,8 @@ static void InterpolateRoadCachedOneWayStates() const RoadBits bits = GetAnyRoadBits(tile, RTT_ROAD, true); if (CountBits(bits) != 2) continue; - uint8_t first_bit = FIND_FIRST_BIT(bits); - uint8_t second_bit = FIND_FIRST_BIT(KillFirstBit(bits)); + uint8_t first_bit = FindFirstBit(bits); + uint8_t second_bit = FindFirstBit(KillFirstBit(bits)); InterpolateRoadResult first_irr = InterpolateRoadFollowRoadBit(tile, first_bit); InterpolateRoadResult second_irr = first_irr; if (first_irr != IRR_NONE) { @@ -2734,7 +2734,7 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u case RCOWS_SIDE_JUNCTION: case RCOWS_SIDE_JUNCTION_NO_EXIT: trackdirbits = (TrackdirBits)((_road_trackbits[bits] * 0x101) & ~(_settings_game.vehicle.road_side ? left_turns : right_turns)); - if (rcows == RCOWS_SIDE_JUNCTION_NO_EXIT) trackdirbits &= ~no_exit_turns[FIND_FIRST_BIT(bits ^ ROAD_ALL) & 3]; + if (rcows == RCOWS_SIDE_JUNCTION_NO_EXIT) trackdirbits &= ~no_exit_turns[FindFirstBit(bits ^ ROAD_ALL) & 3]; break; default: diff --git a/src/road_map.h b/src/road_map.h index 181d199d38..40b6f2d810 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -319,7 +319,7 @@ inline bool HasTownOwnedRoad(TileIndex t) } /** Which directions are disallowed ? */ -enum DisallowedRoadDirections { +enum DisallowedRoadDirections : uint8_t { DRD_NONE, ///< None of the directions are disallowed DRD_SOUTHBOUND, ///< All southbound traffic is disallowed (Trackdir 8-13 is allowed) DRD_NORTHBOUND, ///< All northbound traffic is disallowed (Trackdir 0-5 is allowed) diff --git a/src/road_type.h b/src/road_type.h index 508334cbe8..31ff734fcd 100644 --- a/src/road_type.h +++ b/src/road_type.h @@ -52,7 +52,7 @@ DECLARE_ENUM_AS_BIT_SET(RoadTypes) * This enumeration defines the possible road parts which * can be build on a tile. */ -enum RoadBits { +enum RoadBits : uint8_t { ROAD_NONE = 0U, ///< No road-part is build ROAD_NW = 1U, ///< North-west part ROAD_SW = 2U, ///< South-west part diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 4c69a6a892..d33e5bcdf1 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1255,7 +1255,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection /* Vehicle expected a choice here, invalidate its path. */ v->cached_path->clear(); } - return_track(FindFirstBit2x64(trackdirs)); + return_track(FindFirstBit(trackdirs)); } /* Path cache is out of date, clear it */ diff --git a/src/script/api/script_goal.cpp b/src/script/api/script_goal.cpp index 712f8325c4..5f52108d7e 100644 --- a/src/script/api/script_goal.cpp +++ b/src/script/api/script_goal.cpp @@ -125,7 +125,7 @@ const std::string &text = question->GetEncodedText(); EnforcePreconditionEncodedText(false, text); uint min_buttons = (type == QT_QUESTION ? 1 : 0); - EnforcePrecondition(false, CountBits(buttons) >= min_buttons && CountBits(buttons) <= 3); + EnforcePrecondition(false, CountBits(buttons) >= min_buttons && CountBits(buttons) <= 3); EnforcePrecondition(false, buttons >= 0 && buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT)); EnforcePrecondition(false, (int)type < ::GQT_END); EnforcePrecondition(false, uniqueid >= 0 && uniqueid <= UINT16_MAX); diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index b79d279caf..aa329ddf7a 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -168,7 +168,13 @@ std::string ScriptText::GetEncodedText() seen_ids.clear(); std::string result; auto output = std::back_inserter(result); - this->_GetEncodedText(output, param_count, seen_ids); + if (this->GetActiveInstance()->IsTextParamMismatchAllowed()) { + this->_GetEncodedTextTraditional(output, param_count, seen_ids); + } else { + ParamList params; + this->_FillParamList(params); + this->_GetEncodedText(output, param_count, seen_ids, params); + } if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string))); return result; } @@ -182,13 +188,21 @@ void ScriptText::_TextParamError(std::string msg) } } -void ScriptText::_GetEncodedTextParamsTraditional(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, const std::string &name) +void ScriptText::_GetEncodedTextTraditional(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids) { + const std::string &name = GetGameStringName(this->string); + + if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name)); + seen_ids.push_back(this->string); + + Utf8Encode(output, SCC_ENCODED); + fmt::format_to(output, "{:X}", this->string); + auto write_param_fallback = [&](int idx) { if (std::holds_alternative(this->param[idx])) { int count = 1; // 1 because the string id is included in consumed parameters fmt::format_to(output, ":"); - std::get(this->param[idx])->_GetEncodedText(output, count, seen_ids); + std::get(this->param[idx])->_GetEncodedTextTraditional(output, count, seen_ids); param_count += count; } else if (std::holds_alternative(this->param[idx])) { fmt::format_to(output, ":{:X}", std::get(this->param[idx])); @@ -228,7 +242,7 @@ void ScriptText::_GetEncodedTextParamsTraditional(std::back_insert_iterator(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids); + std::get(this->param[cur_idx++])->_GetEncodedTextTraditional(output, count, seen_ids); if (count != cur_param.consumes) { this->_TextParamError(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, cur_idx, count - 1, cur_param.consumes - 1)); } @@ -256,9 +270,21 @@ void ScriptText::_GetEncodedTextParamsTraditional(std::back_insert_iteratorparamc; i++) { write_param_fallback(i); } + + seen_ids.pop_back(); +} + +void ScriptText::_FillParamList(ParamList ¶ms) +{ + for (int i = 0; i < this->paramc; i++) { + Param *p = &this->param[i]; + params.emplace_back(this->string, i, p); + if (!std::holds_alternative(*p)) continue; + std::get(*p)->_FillParamList(params); + } } -void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids) +void ScriptText::_GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args) { const std::string &name = GetGameStringName(this->string); @@ -268,70 +294,52 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, Utf8Encode(output, SCC_ENCODED); fmt::format_to(output, "{:X}", this->string); - if (this->GetActiveInstance()->IsTextParamMismatchAllowed()) { - this->_GetEncodedTextParamsTraditional(output, param_count, seen_ids, name); - seen_ids.pop_back(); - return; - } - const StringParams ¶ms = GetGameStringParams(this->string); - int cur_idx = 0; - int prev_string = -1; - int prev_idx = -1; - int prev_count = -1; + + size_t idx = 0; + auto get_next_arg = [&]() { + if (idx >= args.size()) throw Script_FatalError(fmt::format("{}({}): Not enough parameters", name, param_count + 1)); + ParamCheck &pc = args[idx++]; + if (pc.owner != this->string) ScriptLog::Warning(fmt::format("{}({}): Consumes {}({})", name, param_count + 1, GetGameStringName(pc.owner), pc.idx + 1)); + return pc.param; + }; + auto skip_args = [&](size_t nb) { idx += nb; }; for (const StringParam &cur_param : params) { - if (cur_idx >= this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name)); - - if (prev_string != -1) { - /* The previous substring added more parameters than expected, means we will consume them but can't properly validate them. */ - for (int i = 0; i < cur_param.consumes; i++) { - if (prev_idx < prev_count) { - ScriptLog::Warning(fmt::format("{}: Parameter {} uses parameter {} from substring {} and cannot be validated", name, param_count + i, prev_idx++, prev_string)); - } else { - /* No more extra parameters, assume SQInteger are expected. */ - if (cur_idx >= this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name)); - if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i)); - fmt::format_to(output, ":{:X}", std::get(this->param[cur_idx++])); - } - } - if (prev_idx == prev_count) { - /* Re-enable validation. */ - prev_string = -1; + switch (cur_param.type) { + case StringParam::UNUSED: + skip_args(cur_param.consumes); + break; + + case StringParam::RAW_STRING: { + Param *p = get_next_arg(); + if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); + fmt::format_to(output, ":\"{}\"", std::get(*p)); + break; } - } else { - switch (cur_param.type) { - case StringParam::RAW_STRING: - if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a raw string", name, param_count)); - fmt::format_to(output, ":\"{}\"", std::get(this->param[cur_idx++])); - break; - case StringParam::STRING: { - if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a substring", name, param_count)); - int count = 0; - fmt::format_to(output, ":"); - std::get(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids); - if (++count != cur_param.consumes) { - ScriptLog::Error(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, param_count, count - 1, cur_param.consumes - 1)); - /* Fill missing params if needed. */ - for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0"); - /* Disable validation for the extra params if any. */ - if (count > cur_param.consumes) { - prev_string = param_count; - prev_idx = cur_param.consumes - 1; - prev_count = count - 1; - } - } - break; + case StringParam::STRING: { + Param *p = get_next_arg(); + if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); + int count = 0; + fmt::format_to(output, ":"); + ScriptTextRef &ref = std::get(*p); + ref->_GetEncodedText(output, count, seen_ids, args.subspan(idx)); + if (++count != cur_param.consumes) { + ScriptLog::Error(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1)); + /* Fill missing params if needed. */ + for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0"); } - - default: - if (cur_idx + cur_param.consumes > this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name)); - for (int i = 0; i < cur_param.consumes; i++) { - if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i)); - fmt::format_to(output, ":{:X}", std::get(this->param[cur_idx++])); - } + skip_args(cur_param.consumes - 1); + break; } + + default: + for (int i = 0; i < cur_param.consumes; i++) { + Param *p = get_next_arg(); + if (!std::holds_alternative(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); + fmt::format_to(output, ":{:X}", std::get(*p)); + } } param_count += cur_param.consumes; diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 1954ffe5fe..74db795a91 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -130,13 +130,32 @@ public: private: using ScriptTextRef = ScriptObjectRef; using StringIDList = std::vector; + using Param = std::variant; + + struct ParamCheck { + StringID owner; + int idx; + Param *param; + + ParamCheck(StringID owner, int idx, Param *param) : owner(owner), idx(idx), param(param) {} + }; + + using ParamList = std::vector; + using ParamSpan = std::span; StringID string; - std::variant param[SCRIPT_TEXT_MAX_PARAMETERS]; + Param param[SCRIPT_TEXT_MAX_PARAMETERS]; int paramc; void _TextParamError(std::string msg); - void _GetEncodedTextParamsTraditional(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, const std::string &name); + + /** + * Internal function to recursively fill a list of parameters. + * The parameters are added as _GetEncodedText used to encode them + * before the addition of parameter validation. + * @param params The list of parameters to fill. + */ + void _FillParamList(ParamList ¶ms); /** * Internal function for recursive calling this function over multiple @@ -145,7 +164,9 @@ private: * @param param_count The number of parameters that are in the string. * @param seen_ids The list of seen StringID. */ - void _GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids); + void _GetEncodedText(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args); + + void _GetEncodedTextTraditional(std::back_insert_iterator &output, int ¶m_count, StringIDList &seen_ids); /** * Set a parameter, where the value is the first item on the stack. diff --git a/src/signal.cpp b/src/signal.cpp index 5113783210..f8bdba199d 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -360,7 +360,7 @@ static SigInfo ExploreSegment(Owner owner) Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir SignalType sig = GetSignalType(tile, track); - Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101) & _enterdir_to_trackdirbits[enterdir]); + Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101U) & _enterdir_to_trackdirbits[enterdir]); Trackdir reversedir = ReverseTrackdir(trackdir); /* add (tile, reversetrackdir) to 'to-be-updated' set when there is * ANY conventional signal in REVERSE direction @@ -616,7 +616,7 @@ uint8_t GetForwardAspectFollowingTrack(TileIndex tile, Trackdir trackdir) tracks = reserved_bits; } - Track track = (Track)FIND_FIRST_BIT(tracks); + Track track = (Track)FindFirstBit(tracks); trackdir = TrackEnterdirToTrackdir(track, ReverseDiagDir(enterdir)); if (HasSignals(tile)) { @@ -673,7 +673,7 @@ uint8_t GetForwardAspectFollowingTrack(TileIndex tile, Trackdir trackdir) tracks = reserved_bits; } - Track track = (Track)FIND_FIRST_BIT(tracks); + Track track = (Track)FindFirstBit(tracks); trackdir = TrackEnterdirToTrackdir(track, ReverseDiagDir(enterdir)); if (IsTunnelBridgeWithSignalSimulation(tile) && HasTrack(GetAcrossTunnelBridgeTrackBits(tile), track)) { @@ -1336,7 +1336,7 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8_t aspect) tracks = reserved_bits; } - Track track = (Track)FIND_FIRST_BIT(tracks); + Track track = (Track)FindFirstBit(tracks); trackdir = TrackEnterdirToTrackdir(track, ReverseDiagDir(enterdir)); if (HasSignals(tile)) { @@ -1404,7 +1404,7 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8_t aspect) tracks = reserved_bits; } - Track track = (Track)FIND_FIRST_BIT(tracks); + Track track = (Track)FindFirstBit(tracks); trackdir = TrackEnterdirToTrackdir(track, ReverseDiagDir(enterdir)); if (TrackdirEntersTunnelBridge(tile, trackdir)) { diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp index 927e12ff9f..d3031d6718 100644 --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -295,7 +295,7 @@ uint8_t LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, s if (below != 0) { SetBit(keep_levels, FindLastBit(below)); } else { - SetBit(keep_levels, FindFirstBit((~below) & available_levels)); + SetBit(keep_levels, FindFirstBit((~below) & available_levels)); } } skip_levels = available_levels & (~keep_levels); diff --git a/src/strings.cpp b/src/strings.cpp index ad0281ded7..8d4e00b5e2 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -2229,17 +2229,11 @@ bool ReadLanguagePack(const LanguageMetadata *lang) return false; } -#if TTD_ENDIAN == TTD_BIG_ENDIAN - for (uint i = 0; i < TEXT_TAB_END; i++) { - lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]); - } -#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ - std::array tab_start, tab_num; uint count = 0; for (uint i = 0; i < TEXT_TAB_END; i++) { - uint16_t num = lang_pack->offsets[i]; + uint16_t num = FROM_LE16(lang_pack->offsets[i]); if (num > TAB_SIZE) return false; tab_start[i] = count; diff --git a/src/tests/bitmath_func.cpp b/src/tests/bitmath_func.cpp index 55e0b0eeea..6ab2697854 100644 --- a/src/tests/bitmath_func.cpp +++ b/src/tests/bitmath_func.cpp @@ -21,7 +21,6 @@ TEST_CASE("FindLastBit tests") CHECK(FindLastBit(0) == 0); CHECK(FindLastBit(0) == 0); CHECK(FindLastBit(0) == 0); - CHECK(FindLastBit64(0) == 0); for (uint i = 0; i < 8; i++) { uint8_t t = (uint8_t)(1 << i); @@ -29,7 +28,6 @@ TEST_CASE("FindLastBit tests") CHECK(FindLastBit(t) == i); CHECK(FindLastBit(t) == i); CHECK(FindLastBit(t) == i); - CHECK(FindLastBit64(t) == i); } for (uint i = 8; i < 16; i++) { @@ -37,22 +35,19 @@ TEST_CASE("FindLastBit tests") CHECK(FindLastBit(t) == i); CHECK(FindLastBit(t) == i); CHECK(FindLastBit(t) == i); - CHECK(FindLastBit64(t) == i); } for (uint i = 16; i < 32; i++) { uint32_t t = (1 << i); CHECK(FindLastBit(t) == i); CHECK(FindLastBit(t) == i); - CHECK(FindLastBit64(t) == i); } for (uint i = 32; i < 64; i++) { uint64_t t = (((uint64_t)1) << i); CHECK(FindLastBit(t) == i); - CHECK(FindLastBit64(t) == i); } - CHECK(FindLastBit(0x42) == FindLastBit(0x40)); - CHECK(FindLastBit(0xAAAA) == FindLastBit(0x8000)); + CHECK(FindLastBit(0x42U) == FindLastBit(0x40U)); + CHECK(FindLastBit(0xAAAAU) == FindLastBit(0x8000U)); } diff --git a/src/track_func.h b/src/track_func.h index fb68b9375a..d83be76c75 100644 --- a/src/track_func.h +++ b/src/track_func.h @@ -132,7 +132,7 @@ inline Track RemoveFirstTrack(TrackBits *tracks) { if (*tracks != TRACK_BIT_NONE && *tracks != INVALID_TRACK_BIT) { dbg_assert((*tracks & ~TRACK_BIT_MASK) == TRACK_BIT_NONE); - Track first = (Track)FIND_FIRST_BIT(*tracks); + Track first = (Track)FindFirstBit(*tracks); ClrBit(*tracks, first); return first; } @@ -157,7 +157,7 @@ inline Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs) { if (*trackdirs != TRACKDIR_BIT_NONE && *trackdirs != INVALID_TRACKDIR_BIT) { dbg_assert((*trackdirs & ~TRACKDIR_BIT_MASK) == TRACKDIR_BIT_NONE); - Trackdir first = (Trackdir)FindFirstBit2x64(*trackdirs); + Trackdir first = (Trackdir)FindFirstBit(*trackdirs); ClrBit(*trackdirs, first); return first; } @@ -176,7 +176,7 @@ inline Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs) */ inline Track FindFirstTrack(TrackBits tracks) { - return (tracks != TRACK_BIT_NONE && tracks != INVALID_TRACK_BIT) ? (Track)FIND_FIRST_BIT(tracks) : INVALID_TRACK; + return (tracks != TRACK_BIT_NONE && tracks != INVALID_TRACK_BIT) ? (Track)FindFirstBit(tracks) : INVALID_TRACK; } /** @@ -193,7 +193,7 @@ inline Track FindFirstTrack(TrackBits tracks) inline Track TrackBitsToTrack(TrackBits tracks) { dbg_assert(tracks == INVALID_TRACK_BIT || (tracks != TRACK_BIT_NONE && KillFirstBit(tracks & TRACK_BIT_MASK) == TRACK_BIT_NONE)); - return tracks != INVALID_TRACK_BIT ? (Track)FIND_FIRST_BIT(tracks & TRACK_BIT_MASK) : INVALID_TRACK; + return tracks != INVALID_TRACK_BIT ? (Track)FindFirstBit(tracks & TRACK_BIT_MASK) : INVALID_TRACK; } /** @@ -211,7 +211,7 @@ inline Track TrackBitsToTrack(TrackBits tracks) inline Trackdir FindFirstTrackdir(TrackdirBits trackdirs) { dbg_assert((trackdirs & ~TRACKDIR_BIT_MASK) == TRACKDIR_BIT_NONE); - return (trackdirs != TRACKDIR_BIT_NONE) ? (Trackdir)FindFirstBit2x64(trackdirs) : INVALID_TRACKDIR; + return (trackdirs != TRACKDIR_BIT_NONE) ? (Trackdir)FindFirstBit(trackdirs) : INVALID_TRACKDIR; } /* diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 790a8a413a..38b2b05857 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -5733,7 +5733,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT); /* Update XY to reflect the entrance to the new tile, and select the direction to use */ - const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir]; + const byte *b = _initial_tile_subcoord[FindFirstBit(chosen_track)][enterdir]; gp.x = (gp.x & ~0xF) | b[0]; gp.y = (gp.y & ~0xF) | b[1]; Direction chosen_dir = (Direction)b[2]; diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h index aa93a36858..49f956cb58 100644 --- a/src/tunnelbridge_map.h +++ b/src/tunnelbridge_map.h @@ -583,7 +583,7 @@ inline void SetTunnelBridgeRestrictedSignal(TileIndex tile, bool is_restricted) inline Trackdir GetTunnelBridgeExitTrackdir(TileIndex t, DiagDirection tunnel_bridge_dir) { - return TrackEnterdirToTrackdir((Track)FIND_FIRST_BIT(GetAcrossTunnelBridgeTrackBits(t)), ReverseDiagDir(tunnel_bridge_dir)); + return TrackEnterdirToTrackdir((Track)FindFirstBit(GetAcrossTunnelBridgeTrackBits(t)), ReverseDiagDir(tunnel_bridge_dir)); } inline Trackdir GetTunnelBridgeExitTrackdir(TileIndex t) @@ -593,7 +593,7 @@ inline Trackdir GetTunnelBridgeExitTrackdir(TileIndex t) inline Trackdir GetTunnelBridgeEntranceTrackdir(TileIndex t, DiagDirection tunnel_bridge_dir) { - return TrackExitdirToTrackdir((Track)FIND_FIRST_BIT(GetAcrossTunnelBridgeTrackBits(t)), tunnel_bridge_dir); + return TrackExitdirToTrackdir((Track)FindFirstBit(GetAcrossTunnelBridgeTrackBits(t)), tunnel_bridge_dir); } inline Trackdir GetTunnelBridgeEntranceTrackdir(TileIndex t)