Merge branch 'master' into jgrpp

# Conflicts:
#	src/core/bitmath_func.cpp
#	src/core/bitmath_func.hpp
#	src/core/geometry_type.hpp
#	src/game/game_text.hpp
#	src/graph_gui.cpp
#	src/pathfinder/npf/npf.cpp
#	src/script/api/script_text.cpp
#	src/spritecache.cpp
#	src/track_func.h
pull/642/head
Jonathan G Rennison 3 months ago
commit 5404be172c

@ -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;

@ -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

@ -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 <http://www.gnu.org/licenses/>.
*/
/** @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<uint32_t>(x));
return FindFirstBit32(static_cast<uint32_t>(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;
}

@ -10,6 +10,7 @@
#ifndef BITMATH_FUNC_HPP
#define BITMATH_FUNC_HPP
#include <bit>
#include <type_traits>
/**
@ -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<uint>(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 <typename T>
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<T>::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<T>) {
return std::countr_zero<std::underlying_type_t<T>>(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 <typename T>
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<T>::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<T>(1) - std::countl_zero<T>(x);
}
/**
@ -315,32 +244,13 @@ inline T KillFirstBit(T value)
* @return the number of bits.
*/
template <typename T>
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<T>::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<T>) {
return std::popcount<std::underlying_type_t<T>>(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 <typename T>
inline bool IsOddParity(T value)
{
static_assert(sizeof(T) <= sizeof(unsigned long long));
#ifdef WITH_BITMATH_BUILTINS
typename std::make_unsigned<T>::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<T>(value) & 1;
return CountBits(unsigned_value) & 1;
#endif
}

@ -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 */

@ -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;
};

@ -290,9 +290,15 @@ static void ExtractStringParams(const StringData &data, StringParamsList &params
StringParams &param = 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);
}
}
}

@ -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<StringParam>;
using StringParamsList = std::vector<StringParams>;

@ -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;

@ -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. */

@ -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<GlyphID> &GetGlyphs() const = 0;
virtual const std::vector<Point> &GetPositions() const = 0;
virtual int GetLeading() const = 0;
virtual const int *GetGlyphToCharMap() const = 0;
virtual const std::vector<int> &GetGlyphToCharMap() const = 0;
};
/** A single line worth of VisualRuns. */

@ -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<GlyphID> glyphs; ///< The glyphs we're drawing.
std::vector<float> positions; ///< The positions of the glyphs.
std::vector<Point> positions; ///< The positions of the glyphs.
std::vector<int> 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<int>(this->glyphs.size()); }
const GlyphID *GetGlyphs() const override { return this->glyphs.data(); }
const float *GetPositions() const override { return this->positions.data(); }
const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
const std::vector<Point> &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<int> &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;
}
/**

@ -45,7 +45,7 @@ public:
std::vector<GlyphID> glyphs; ///< The glyphs of the run. Valid after Shape() is called.
std::vector<int> advance; ///< The advance (width) of the glyphs. Valid after Shape() is called.
std::vector<int> glyph_to_char; ///< The mapping from glyphs to characters. Valid after Shape() is called.
std::vector<float> positions; ///< The positions of the glyphs. Valid after Shape() is called.
std::vector<Point> 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<GlyphID> glyphs;
std::vector<float> positions;
std::vector<Point> positions;
std::vector<int> 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<GlyphID> &GetGlyphs() const override { return this->glyphs; }
const std::vector<Point> &GetPositions() const override { return this->positions; }
const std::vector<int> &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;

@ -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<uint64_t>(x_axis_offset) + FindLastBit<uint64_t>(abs(datapoint));
int mult_range = FindLastBit<uint32_t>(x_axis_offset) + FindLastBit<uint64_t>(abs(datapoint));
int reduce_range = std::max(mult_range - 31, 0);
/* Handle negative values differently (don't shift sign) */

@ -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,

@ -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

@ -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

@ -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}

@ -651,6 +651,9 @@ static void MidiThreadProc()
TransmitNotesOff(_buffer, block_time, cur_time);
MemSetT<byte>(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);

@ -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<std::mutex> 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<byte>(_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");

@ -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;
}
}
}

@ -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<HouseZones>(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;

@ -73,7 +73,7 @@ public:
class CoreTextVisualRun : public ParagraphLayouter::VisualRun {
private:
std::vector<GlyphID> glyphs;
std::vector<float> positions;
std::vector<Point> positions;
std::vector<int> 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<GlyphID> &GetGlyphs() const override { return this->glyphs; }
const std::vector<Point> &GetPositions() const override { return this->positions; }
const std::vector<int> &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);
}
/**

@ -34,6 +34,8 @@ static std::tuple<std::string, std::string> 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)) };
}

@ -75,7 +75,7 @@ public:
class UniscribeVisualRun : public ParagraphLayouter::VisualRun {
private:
std::vector<GlyphID> glyphs;
std::vector<float> positions;
std::vector<Point> positions;
std::vector<WORD> 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<int> 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<GlyphID> &GetGlyphs() const override { return this->glyphs; }
const std::vector<Point> &GetPositions() const override { return this->positions; }
const std::vector<int> &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<int> &UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const
{
if (this->glyph_to_char == nullptr) {
this->glyph_to_char = CallocT<int>(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. */

@ -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;
}

@ -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);

@ -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);

@ -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)))) {

@ -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)

@ -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). */

@ -1172,7 +1172,7 @@ bool FloodHalftile(TileIndex t)
TrackBits to_remove = lower_track & rail_bits;
if (to_remove != 0) {
Backup<CompanyID> 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;

@ -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<RoadBits>(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:

@ -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)

@ -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

@ -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 */

@ -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<uint64_t>(buttons) >= min_buttons && CountBits<uint64_t>(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);

@ -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<std::string> &output, int &param_count, StringIDList &seen_ids, const std::string &name)
void ScriptText::_GetEncodedTextTraditional(std::back_insert_iterator<std::string> &output, int &param_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<ScriptTextRef>(this->param[idx])) {
int count = 1; // 1 because the string id is included in consumed parameters
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[idx])->_GetEncodedText(output, count, seen_ids);
std::get<ScriptTextRef>(this->param[idx])->_GetEncodedTextTraditional(output, count, seen_ids);
param_count += count;
} else if (std::holds_alternative<SQInteger>(this->param[idx])) {
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[idx]));
@ -228,7 +242,7 @@ void ScriptText::_GetEncodedTextParamsTraditional(std::back_insert_iterator<std:
}
int count = 1; // 1 because the string id is included in consumed parameters
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids);
std::get<ScriptTextRef>(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_iterator<std:
for (int i = cur_idx; i < this->paramc; i++) {
write_param_fallback(i);
}
seen_ids.pop_back();
}
void ScriptText::_FillParamList(ParamList &params)
{
for (int i = 0; i < this->paramc; i++) {
Param *p = &this->param[i];
params.emplace_back(this->string, i, p);
if (!std::holds_alternative<ScriptTextRef>(*p)) continue;
std::get<ScriptTextRef>(*p)->_FillParamList(params);
}
}
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids)
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids, ParamSpan args)
{
const std::string &name = GetGameStringName(this->string);
@ -268,70 +294,52 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &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 &params = 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<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(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<std::string>(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
fmt::format_to(output, ":\"{}\"", std::get<std::string>(*p));
break;
}
} else {
switch (cur_param.type) {
case StringParam::RAW_STRING:
if (!std::holds_alternative<std::string>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a raw string", name, param_count));
fmt::format_to(output, ":\"{}\"", std::get<std::string>(this->param[cur_idx++]));
break;
case StringParam::STRING: {
if (!std::holds_alternative<ScriptTextRef>(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<ScriptTextRef>(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<ScriptTextRef>(*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<ScriptTextRef>(*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<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(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<SQInteger>(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(*p));
}
}
param_count += cur_param.consumes;

@ -130,13 +130,32 @@ public:
private:
using ScriptTextRef = ScriptObjectRef<ScriptText>;
using StringIDList = std::vector<StringID>;
using Param = std::variant<SQInteger, std::string, ScriptTextRef>;
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<ParamCheck>;
using ParamSpan = std::span<ParamCheck>;
StringID string;
std::variant<SQInteger, std::string, ScriptTextRef> param[SCRIPT_TEXT_MAX_PARAMETERS];
Param param[SCRIPT_TEXT_MAX_PARAMETERS];
int paramc;
void _TextParamError(std::string msg);
void _GetEncodedTextParamsTraditional(std::back_insert_iterator<std::string> &output, int &param_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 &params);
/**
* 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<std::string> &output, int &param_count, StringIDList &seen_ids);
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids, ParamSpan args);
void _GetEncodedTextTraditional(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids);
/**
* Set a parameter, where the value is the first item on the stack.

@ -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)) {

@ -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<uint8_t>((~below) & available_levels));
}
}
skip_levels = available_levels & (~keep_levels);

@ -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<uint, TEXT_TAB_END> 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;

@ -21,7 +21,6 @@ TEST_CASE("FindLastBit tests")
CHECK(FindLastBit<uint16_t>(0) == 0);
CHECK(FindLastBit<uint32_t>(0) == 0);
CHECK(FindLastBit<uint64_t>(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<uint16_t>(t) == i);
CHECK(FindLastBit<uint32_t>(t) == i);
CHECK(FindLastBit<uint64_t>(t) == i);
CHECK(FindLastBit64(t) == i);
}
for (uint i = 8; i < 16; i++) {
@ -37,22 +35,19 @@ TEST_CASE("FindLastBit tests")
CHECK(FindLastBit<uint16_t>(t) == i);
CHECK(FindLastBit<uint32_t>(t) == i);
CHECK(FindLastBit<uint64_t>(t) == i);
CHECK(FindLastBit64(t) == i);
}
for (uint i = 16; i < 32; i++) {
uint32_t t = (1 << i);
CHECK(FindLastBit<uint32_t>(t) == i);
CHECK(FindLastBit<uint64_t>(t) == i);
CHECK(FindLastBit64(t) == i);
}
for (uint i = 32; i < 64; i++) {
uint64_t t = (((uint64_t)1) << i);
CHECK(FindLastBit<uint64_t>(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));
}

@ -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;
}
/*

@ -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];

@ -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)

Loading…
Cancel
Save