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)