Codechange: make TimerGameCalendar Date and Year types strongly typed (#10761)

This commit is contained in:
Patric Stout 2023-08-12 20:14:21 +02:00 committed by GitHub
parent 0238a2b567
commit 299570b2c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 390 additions and 203 deletions

View File

@ -105,7 +105,7 @@ static int32_t ClickChangeDateCheat(int32_t new_value, int32_t change_direction)
{
/* Don't allow changing to an invalid year, or the current year. */
auto new_year = Clamp(TimerGameCalendar::Year(new_value), MIN_YEAR, MAX_YEAR);
if (new_year == TimerGameCalendar::year) return TimerGameCalendar::year;
if (new_year == TimerGameCalendar::year) return static_cast<int32_t>(TimerGameCalendar::year);
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
@ -125,7 +125,7 @@ static int32_t ClickChangeDateCheat(int32_t new_value, int32_t change_direction)
InvalidateWindowClassesData(WC_TRUCK_STATION, 0);
InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
ResetSignalVariant();
return TimerGameCalendar::year;
return static_cast<int32_t>(TimerGameCalendar::year);
}
/**

View File

@ -437,7 +437,7 @@ struct CompanyFinancesWindow : Window {
auto age = std::min(TimerGameCalendar::year - c->inaugurated_year, TimerGameCalendar::Year(2));
int wid_offset = widget - WID_CF_EXPS_PRICE1;
if (wid_offset <= age) {
DrawYearColumn(r, TimerGameCalendar::year - (age - wid_offset), c->yearly_expenses[age - wid_offset]);
DrawYearColumn(r, TimerGameCalendar::year - (age - wid_offset), c->yearly_expenses[static_cast<int32_t>(age - wid_offset)]);
}
break;
}

View File

@ -28,8 +28,8 @@ struct fmt::formatter<E, Char, std::enable_if_t<std::is_enum<E>::value>> : fmt::
};
template <typename T, typename Char>
struct fmt::formatter<T, Char, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value>> : fmt::formatter<typename T::Type> {
using underlying_type = typename T::Type;
struct fmt::formatter<T, Char, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value>> : fmt::formatter<typename T::BaseType> {
using underlying_type = typename T::BaseType;
using parent = typename fmt::formatter<underlying_type>;
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx) {

View File

@ -10,6 +10,7 @@
#ifndef MATH_FUNC_HPP
#define MATH_FUNC_HPP
#include "strong_typedef_type.hpp"
/**
* Returns the absolute value of (scalar) variable.
@ -162,7 +163,7 @@ static inline uint ClampU(const uint a, const uint min, const uint max)
* for the return type.
* @see Clamp(int, int, int)
*/
template <typename To, typename From>
template <typename To, typename From, std::enable_if_t<std::is_integral<From>::value, int> = 0>
constexpr To ClampTo(From value)
{
static_assert(std::numeric_limits<To>::is_integer, "Do not clamp from non-integer values");
@ -213,6 +214,15 @@ constexpr To ClampTo(From value)
return static_cast<To>(std::min<BiggerType>(value, std::numeric_limits<To>::max()));
}
/**
* Specialization of ClampTo for #StrongType::Typedef.
*/
template <typename To, typename From, std::enable_if_t<std::is_base_of<StrongTypedefBase, From>::value, int> = 0>
constexpr To ClampTo(From value)
{
return ClampTo<To>(static_cast<typename From::BaseType>(value));
}
/**
* Returns the (absolute) difference between two (scalar) variables
*
@ -254,10 +264,14 @@ static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
* @param max The maximum of the interval
* @see IsInsideBS()
*/
template <typename T>
template <typename T, std::enable_if_t<std::disjunction_v<std::is_convertible<T, size_t>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
static constexpr inline bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
{
return (size_t)(x - min) < (max - min);
if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
return (size_t)(static_cast<typename T::BaseType>(x) - min) < (max - min);
} else {
return (size_t)(x - min) < (max - min);
}
}
/**

View File

@ -10,74 +10,199 @@
#ifndef STRONG_TYPEDEF_TYPE_HPP
#define STRONG_TYPEDEF_TYPE_HPP
/** Non-templated base for #StrongTypedef for use with type trait queries. */
#include "../3rdparty/fmt/format.h"
/** Non-templated base for #StrongType::Typedef for use with type trait queries. */
struct StrongTypedefBase {};
/**
* Templated helper to make a type-safe 'typedef' representing a single POD value.
* A normal 'typedef' is not distinct from its base type and will be treated as
* identical in many contexts. This class provides a distinct type that can still
* be assign from and compared to values of its base type.
*
* @note This is meant to be used as a base class, not directly.
* @tparam T Storage type
* @tparam Tthis Type of the derived class (i.e. the concrete usage of this class).
*/
template <class T, class Tthis>
struct StrongTypedef : StrongTypedefBase {
using Type = T;
namespace StrongType {
/**
* Mix-in which makes the new Typedef comparable with itself and its base type.
*/
struct Compare {
template <typename TType, typename TBaseType>
struct mixin {
friend constexpr bool operator ==(const TType &lhs, const TType &rhs) { return lhs.value == rhs.value; }
friend constexpr bool operator ==(const TType &lhs, const TBaseType &rhs) { return lhs.value == rhs; }
T value{}; ///< Backing storage field.
friend constexpr bool operator !=(const TType &lhs, const TType &rhs) { return lhs.value != rhs.value; }
friend constexpr bool operator !=(const TType &lhs, const TBaseType &rhs) { return lhs.value != rhs; }
debug_inline constexpr StrongTypedef() = default;
debug_inline constexpr StrongTypedef(const StrongTypedef &o) = default;
debug_inline constexpr StrongTypedef(StrongTypedef &&o) = default;
friend constexpr bool operator <=(const TType &lhs, const TType &rhs) { return lhs.value <= rhs.value; }
friend constexpr bool operator <=(const TType &lhs, const TBaseType &rhs) { return lhs.value <= rhs; }
debug_inline constexpr StrongTypedef(const T &value) : value(value) {}
friend constexpr bool operator <(const TType &lhs, const TType &rhs) { return lhs.value < rhs.value; }
friend constexpr bool operator <(const TType &lhs, const TBaseType &rhs) { return lhs.value < rhs; }
debug_inline constexpr Tthis &operator =(const Tthis &rhs) { this->value = rhs.value; return static_cast<Tthis &>(*this); }
debug_inline constexpr Tthis &operator =(Tthis &&rhs) { this->value = std::move(rhs.value); return static_cast<Tthis &>(*this); }
debug_inline constexpr Tthis &operator =(const T &rhs) { this->value = rhs; return static_cast<Tthis &>(*this); }
friend constexpr bool operator >=(const TType &lhs, const TType &rhs) { return lhs.value >= rhs.value; }
friend constexpr bool operator >=(const TType &lhs, const TBaseType &rhs) { return lhs.value >= rhs; }
explicit constexpr operator T() const { return this->value; }
friend constexpr bool operator >(const TType &lhs, const TType &rhs) { return lhs.value > rhs.value; }
friend constexpr bool operator >(const TType &lhs, const TBaseType &rhs) { return lhs.value > rhs; }
};
};
constexpr bool operator ==(const Tthis &rhs) const { return this->value == rhs.value; }
constexpr bool operator !=(const Tthis &rhs) const { return this->value != rhs.value; }
constexpr bool operator ==(const T &rhs) const { return this->value == rhs; }
constexpr bool operator !=(const T &rhs) const { return this->value != rhs; }
};
/**
* Mix-in which makes the new Typedef behave more like an integer. This means you can add and subtract from it.
*
* Operators like divide, multiply and module are explicitly denied, as that often makes little sense for the
* new type. If you want to do these actions on the new Typedef, you are better off first casting it to the
* base type.
*/
struct Integer {
template <typename TType, typename TBaseType>
struct mixin {
friend constexpr TType &operator ++(TType &lhs) { lhs.value++; return lhs; }
friend constexpr TType &operator --(TType &lhs) { lhs.value--; return lhs; }
friend constexpr TType operator ++(TType &lhs, int) { TType res = lhs; lhs.value++; return res; }
friend constexpr TType operator --(TType &lhs, int) { TType res = lhs; lhs.value--; return res; }
/**
* Extension of #StrongTypedef with operators for addition and subtraction.
* @tparam T Storage type
* @tparam Tthis Type of the derived class (i.e. the concrete usage of this class).
*/
template <class T, class Tthis>
struct StrongIntegralTypedef : StrongTypedef<T, Tthis> {
using StrongTypedef<T, Tthis>::StrongTypedef;
friend constexpr TType &operator +=(TType &lhs, const TType &rhs) { lhs.value += rhs.value; return lhs; }
friend constexpr TType operator +(const TType &lhs, const TType &rhs) { return TType{ lhs.value + rhs.value }; }
friend constexpr TType operator +(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value + rhs }; }
debug_inline constexpr StrongIntegralTypedef() = default;
debug_inline constexpr StrongIntegralTypedef(const StrongIntegralTypedef &o) = default;
debug_inline constexpr StrongIntegralTypedef(StrongIntegralTypedef &&o) = default;
friend constexpr TType &operator -=(TType &lhs, const TType &rhs) { lhs.value -= rhs.value; return lhs; }
friend constexpr TType operator -(const TType &lhs, const TType &rhs) { return TType{ lhs.value - rhs.value }; }
friend constexpr TType operator -(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value - rhs }; }
debug_inline constexpr StrongIntegralTypedef(const T &value) : StrongTypedef<T, Tthis>(value) {}
/* For most new types, the rest of the operators make no sense. For example,
* what does it actually mean to multiply a Year with a value. Or to do a
* bitwise OR on a Date. Or to divide a TileIndex by 2. Conceptually, they
* don't really mean anything. So force the user to first cast it to the
* base type, so the operation no longer returns the new Typedef. */
debug_inline constexpr Tthis &operator =(const Tthis &rhs) { this->value = rhs.value; return static_cast<Tthis &>(*this); }
debug_inline constexpr Tthis &operator =(Tthis &&rhs) { this->value = std::move(rhs.value); return static_cast<Tthis &>(*this); }
debug_inline constexpr Tthis &operator =(const T &rhs) { this->value = rhs; return static_cast<Tthis &>(*this); }
constexpr TType &operator *=(const TType &rhs) = delete;
constexpr TType operator *(const TType &rhs) = delete;
constexpr TType operator *(const TBaseType &rhs) = delete;
constexpr Tthis &operator ++() { this->value++; return static_cast<Tthis &>(*this); }
constexpr Tthis &operator --() { this->value--; return static_cast<Tthis &>(*this); }
constexpr Tthis operator ++(int) { auto res = static_cast<Tthis &>(*this); this->value++; return res; }
constexpr Tthis operator --(int) { auto res = static_cast<Tthis &>(*this); this->value--; return res; }
constexpr TType &operator /=(const TType &rhs) = delete;
constexpr TType operator /(const TType &rhs) = delete;
constexpr TType operator /(const TBaseType &rhs) = delete;
constexpr Tthis &operator +=(const Tthis &rhs) { this->value += rhs.value; return *static_cast<Tthis *>(this); }
constexpr Tthis &operator -=(const Tthis &rhs) { this->value -= rhs.value; return *static_cast<Tthis *>(this); }
constexpr TType &operator %=(const TType &rhs) = delete;
constexpr TType operator %(const TType &rhs) = delete;
constexpr TType operator %(const TBaseType &rhs) = delete;
constexpr Tthis operator +(const Tthis &rhs) const { return Tthis{ this->value + rhs.value }; }
constexpr Tthis operator -(const Tthis &rhs) const { return Tthis{ this->value - rhs.value }; }
constexpr Tthis operator +(const T &rhs) const { return Tthis{ this->value + rhs }; }
constexpr Tthis operator -(const T &rhs) const { return Tthis{ this->value - rhs }; }
};
constexpr TType &operator &=(const TType &rhs) = delete;
constexpr TType operator &(const TType &rhs) = delete;
constexpr TType operator &(const TBaseType &rhs) = delete;
constexpr TType &operator |=(const TType &rhs) = delete;
constexpr TType operator |(const TType &rhs) = delete;
constexpr TType operator |(const TBaseType &rhs) = delete;
constexpr TType &operator ^=(const TType &rhs) = delete;
constexpr TType operator ^(const TType &rhs) = delete;
constexpr TType operator ^(const TBaseType &rhs) = delete;
constexpr TType &operator <<=(const TType &rhs) = delete;
constexpr TType operator <<(const TType &rhs) = delete;
constexpr TType operator <<(const TBaseType &rhs) = delete;
constexpr TType &operator >>=(const TType &rhs) = delete;
constexpr TType operator >>(const TType &rhs) = delete;
constexpr TType operator >>(const TBaseType &rhs) = delete;
constexpr TType operator ~() = delete;
constexpr TType operator -() = delete;
};
};
/**
* Mix-in which makes the new Typedef compatible with another type (which is not the base type).
*
* @note The base type of the new Typedef will be cast to the other type; so make sure they are compatible.
*
* @tparam TCompatibleType The other type to be compatible with.
*/
template <typename TCompatibleType>
struct Compatible {
template <typename TType, typename TBaseType>
struct mixin {
friend constexpr bool operator ==(const TType &lhs, TCompatibleType rhs) { return lhs.value == static_cast<TBaseType>(rhs); }
friend constexpr bool operator !=(const TType &lhs, TCompatibleType rhs) { return lhs.value != static_cast<TBaseType>(rhs); }
friend constexpr bool operator <=(const TType &lhs, TCompatibleType rhs) { return lhs.value <= static_cast<TBaseType>(rhs); }
friend constexpr bool operator <(const TType &lhs, TCompatibleType rhs) { return lhs.value < static_cast<TBaseType>(rhs); }
friend constexpr bool operator >=(const TType &lhs, TCompatibleType rhs) { return lhs.value >= static_cast<TBaseType>(rhs); }
friend constexpr bool operator >(const TType &lhs, TCompatibleType rhs) { return lhs.value > static_cast<TBaseType>(rhs); }
friend constexpr TType operator +(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value + rhs) }; }
friend constexpr TType operator -(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value - rhs) }; }
};
};
/**
* Mix-in which makes the new Typedef implicitly convertible to its base type.
*
* Be careful: when allowing implicit conversion, you won't notice if this type is assigned to a compatible, but different, type.
* For example:
*
* StrongType::Typedef<int, struct MyTypeTag, Implicit> a = 1;
* StrongType::Typedef<int, struct MyTypeTag, Implicit> b = 2;
* a = b; // OK
*/
struct Implicit {
template <typename TType, typename TBaseType>
struct mixin {
constexpr operator TBaseType () const { return static_cast<const TType &>(*this).value; }
};
};
/**
* Mix-in which makes the new Typedef explicitly convertible to its base type.
*/
struct Explicit {
template <typename TType, typename TBaseType>
struct mixin {
explicit constexpr operator TBaseType () const { return static_cast<const TType &>(*this).value; }
};
};
/**
* Templated helper to make a type-safe 'typedef' representing a single POD value.
* A normal 'typedef' is not distinct from its base type and will be treated as
* identical in many contexts. This class provides a distinct type that can still
* be assign from and compared to values of its base type.
*
* Example usage:
*
* using MyType = StrongType::Typedef<int, struct MyTypeTag, StrongType::Explicit, StrongType::Compare, StrongType::Integer>;
*
* @tparam TBaseType Type of the derived class (i.e. the concrete usage of this class).
* @tparam TTag An unique struct to keep types of the same TBaseType distinct.
* @tparam TProperties A list of mixins to add to the class.
*/
template <typename TBaseType, typename TTag, typename... TProperties>
struct EMPTY_BASES Typedef : public StrongTypedefBase, public TProperties::template mixin<Typedef<TBaseType, TTag, TProperties...>, TBaseType>... {
using BaseType = TBaseType;
constexpr Typedef() = default;
constexpr Typedef(const Typedef &) = default;
constexpr Typedef(Typedef &&) = default;
constexpr Typedef(const TBaseType &value) : value(value) {}
constexpr Typedef &operator =(const Typedef &rhs) { this->value = rhs.value; return *this; }
constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
constexpr Typedef &operator =(const TBaseType &rhs) { this->value = rhs; return *this; }
/* Only allow TProperties classes access to the internal value. Everyone else needs to do an explicit cast. */
friend struct Explicit;
friend struct Implicit;
friend struct Compare;
friend struct Integer;
template <typename TCompatibleType> friend struct Compatible;
/* GCC / MSVC don't pick up on the "friend struct" above, where CLang does.
* As in our CI we compile for all three targets, it is sufficient to have one
* that errors on this; but nobody should be using "value" directly. Instead,
* use a static_cast<> to convert to the base type. */
#ifdef __clang__
protected:
#endif /* __clang__ */
TBaseType value{};
};
}
#endif /* STRONG_TYPEDEF_TYPE_HPP */

View File

@ -91,9 +91,9 @@ struct SetDateWindow : Window {
case WID_SD_YEAR:
for (TimerGameCalendar::Year i = this->min_year; i <= this->max_year; i++) {
SetDParam(0, i);
list.emplace_back(new DropDownListStringItem(STR_JUST_INT, i, false));
list.emplace_back(new DropDownListStringItem(STR_JUST_INT, static_cast<int32_t>(i), false));
}
selected = this->date.year;
selected = static_cast<int32_t>(this->date.year);
break;
}

View File

@ -58,9 +58,10 @@ static constexpr TimerGameCalendar::Year ORIGINAL_MAX_YEAR = 2090;
*/
static constexpr TimerGameCalendar::Date DateAtStartOfYear(TimerGameCalendar::Year year)
{
uint number_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1);
int32_t year_as_int = static_cast<int32_t>(year);
uint number_of_leap_years = (year == 0) ? 0 : ((year_as_int - 1) / 4 - (year_as_int - 1) / 100 + (year_as_int - 1) / 400 + 1);
return (DAYS_IN_YEAR * year) + number_of_leap_years;
return (DAYS_IN_YEAR * year_as_int) + number_of_leap_years;
}
/**
@ -70,7 +71,7 @@ static constexpr TimerGameCalendar::Date DateAtStartOfYear(TimerGameCalendar::Ye
*/
static inline TimerGameCalendar::Year DateToYear(TimerGameCalendar::Date date)
{
return date / DAYS_IN_LEAP_YEAR;
return static_cast<int32_t>(date) / DAYS_IN_LEAP_YEAR;
}
/**

View File

@ -360,7 +360,7 @@ struct DepotWindow : Window {
DrawSpriteIgnorePadding((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, flag, false, SA_CENTER);
SetDParam(0, v->unitnumber);
DrawString(text, STR_JUST_COMMA, (uint16_t)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? TC_BLACK : TC_RED);
DrawString(text, STR_JUST_COMMA, (v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? TC_BLACK : TC_RED);
}
}

View File

@ -928,7 +928,7 @@ void StartupEconomy()
if (_settings_game.economy.inflation) {
/* Apply inflation that happened before our game start year. */
int months = (std::min(TimerGameCalendar::year, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR) * 12;
int months = static_cast<int32_t>(std::min(TimerGameCalendar::year, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR) * 12;
for (int i = 0; i < months; i++) {
AddInflation(false);
}

View File

@ -662,7 +662,7 @@ void SetYearEngineAgingStops()
/* Base year ending date on half the model life */
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(ei->base_intro + DateAtStartOfYear(ei->lifelength) / 2, &ymd);
TimerGameCalendar::ConvertDateToYMD(ei->base_intro + static_cast<int32_t>(DateAtStartOfYear(ei->lifelength)) / 2, &ymd);
_year_engine_aging_stops = std::max(_year_engine_aging_stops, ymd.year);
}
@ -688,7 +688,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
SavedRandomSeeds saved_seeds;
SaveRandomSeeds(&saved_seeds);
SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^
ei->base_intro ^
static_cast<int32_t>(ei->base_intro) ^
e->type ^
e->GetGRFID());
uint32_t r = Random();
@ -698,7 +698,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
* Note: TTDP uses fixed 1922 */
e->intro_date = ei->base_intro <= TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (TimerGameCalendar::Date)GB(r, 0, 9) + ei->base_intro;
if (e->intro_date <= TimerGameCalendar::date) {
e->age = (aging_date - e->intro_date) >> 5;
e->age = static_cast<int32_t>(aging_date - e->intro_date) >> 5;
e->company_avail = MAX_UVALUE(CompanyMask);
e->flags |= ENGINE_AVAILABLE;
}
@ -710,8 +710,8 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
}
SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^
(re->index << 16) ^ (re->info.base_intro << 12) ^ (re->info.decay_speed << 8) ^
(re->info.lifelength << 4) ^ re->info.retire_early ^
(re->index << 16) ^ (static_cast<int32_t>(re->info.base_intro) << 12) ^ (re->info.decay_speed << 8) ^
(static_cast<int32_t>(re->info.lifelength) << 4) ^ re->info.retire_early ^
e->type ^
e->GetGRFID());
@ -722,7 +722,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
r = Random();
e->reliability_final = GB(r, 16, 14) + 0x3FFF;
e->duration_phase_1 = GB(r, 0, 5) + 7;
e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
e->duration_phase_2 = GB(r, 5, 4) + static_cast<int32_t>(ei->base_life) * 12 - 96;
e->duration_phase_3 = GB(r, 9, 7) + 120;
RestoreRandomSeeds(saved_seeds);

View File

@ -968,7 +968,7 @@ struct GenerateLandscapeWindow : public Window {
/* An empty string means revert to the default */
switch (this->widget_id) {
case WID_GL_HEIGHTMAP_HEIGHT_TEXT: value = MAP_HEIGHT_LIMIT_AUTO_MINIMUM; break;
case WID_GL_START_DATE_TEXT: value = DEF_START_YEAR; break;
case WID_GL_START_DATE_TEXT: value = static_cast<int32_t>(DEF_START_YEAR); break;
case WID_GL_SNOW_COVERAGE_TEXT: value = DEF_SNOW_COVERAGE; break;
case WID_GL_DESERT_COVERAGE_TEXT: value = DEF_DESERT_COVERAGE; break;
case WID_GL_TOWN_PULLDOWN: value = 1; break;

View File

@ -787,7 +787,7 @@ void RunTileLoop()
_tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
/* Get the next tile in sequence using a Galois LFSR. */
tile = (tile >> 1) ^ (-(int32_t)(tile & 1) & feedback);
tile = (static_cast<uint32_t>(tile) >> 1) ^ (-(int32_t)(static_cast<uint32_t>(tile) & 1) & feedback);
}
_cur_tileloop_tile = tile;
@ -935,11 +935,11 @@ static void GenerateTerrain(int type, uint flag)
static void CreateDesertOrRainForest(uint desert_tropic_line)
{
TileIndex update_freq = Map::Size() / 4;
uint update_freq = Map::Size() / 4;
const TileIndexDiffC *data;
for (TileIndex tile = 0; tile != Map::Size(); ++tile) {
if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
if ((static_cast<uint32_t>(tile) % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
if (!IsValidTile(tile)) continue;
@ -960,7 +960,7 @@ static void CreateDesertOrRainForest(uint desert_tropic_line)
}
for (TileIndex tile = 0; tile != Map::Size(); ++tile) {
if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
if ((static_cast<uint32_t>(tile) % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
if (!IsValidTile(tile)) continue;

View File

@ -50,9 +50,9 @@ void FlowMapper::Run(LinkGraphJob &job) const
/* Scale by time the graph has been running without being compressed. Add 1 to avoid
* division by 0 if spawn date == last compression date. This matches
* LinkGraph::Monthly(). */
uint runtime = job.JoinDate() - job.Settings().recalc_time / SECONDS_PER_DAY - job.LastCompression() + 1;
auto runtime = job.JoinDate() - job.Settings().recalc_time / SECONDS_PER_DAY - job.LastCompression() + 1;
for (auto &it : flows) {
it.second.ScaleToMonthly(runtime);
it.second.ScaleToMonthly(static_cast<int32_t>(runtime));
}
}
/* Clear paths. */

View File

@ -65,7 +65,7 @@ void LinkGraph::ShiftDates(TimerGameCalendar::Date interval)
void LinkGraph::Compress()
{
this->last_compression = (TimerGameCalendar::date + this->last_compression) / 2;
this->last_compression = static_cast<int32_t>(TimerGameCalendar::date + this->last_compression) / 2;
for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
this->nodes[node1].supply /= 2;
for (BaseEdge &edge : this->nodes[node1].edges) {

View File

@ -186,7 +186,7 @@ public:
*/
inline static uint Scale(uint val, TimerGameCalendar::Date target_age, TimerGameCalendar::Date orig_age)
{
return val > 0 ? std::max(1U, val * target_age / orig_age) : 0;
return val > 0 ? std::max(1U, val * static_cast<int32_t>(target_age) / static_cast<int32_t>(orig_age)) : 0;
}
/** Bare constructor, only for save/load. */
@ -249,7 +249,7 @@ public:
*/
inline uint Monthly(uint base) const
{
return base * 30 / (TimerGameCalendar::date - this->last_compression + 1);
return base * 30 / static_cast<int32_t>(TimerGameCalendar::date - this->last_compression + 1);
}
NodeID AddNode(const Station *st);

View File

@ -178,7 +178,7 @@ void StateGameLoop_LinkGraphPauseControl()
}
} else if (_pause_mode == PM_UNPAUSED &&
TimerGameCalendar::date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
TimerGameCalendar::date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2 &&
static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2 &&
LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
/* Perform check two TimerGameCalendar::date_fract ticks before we would join, to make
* sure it also works in multiplayer. */
@ -205,7 +205,7 @@ void AfterLoad_LinkGraphPauseControl()
void OnTick_LinkGraph()
{
if (TimerGameCalendar::date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
TimerGameCalendar::Date offset = TimerGameCalendar::date % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY);
TimerGameCalendar::Date offset = static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY);
if (offset == 0) {
LinkGraphSchedule::instance.SpawnNext();
} else if (offset == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2) {

View File

@ -53,7 +53,7 @@ public:
if constexpr (std::is_enum_v<T>) {
this->Write(static_cast<std::underlying_type_t<const T>>(data));
} else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
this->Write(static_cast<typename T::Type>(data));
this->Write(static_cast<typename T::BaseType>(data));
} else {
this->Write(data);
}
@ -146,7 +146,7 @@ public:
if constexpr (std::is_enum_v<T>) {
data = static_cast<T>(this->Read<std::underlying_type_t<T>>());
} else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
data = this->Read<typename T::Type>();
data = this->Read<typename T::BaseType>();
} else {
data = this->Read<T>();
}

View File

@ -227,8 +227,8 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool
}
/* NETWORK_GAME_INFO_VERSION = 3 */
p->Send_uint32(info->game_date);
p->Send_uint32(info->start_date);
p->Send_uint32(static_cast<int32_t>(info->game_date));
p->Send_uint32(static_cast<int32_t>(info->start_date));
/* NETWORK_GAME_INFO_VERSION = 2 */
p->Send_uint8 (info->companies_max);
@ -323,8 +323,8 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
}
case 3:
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
info->game_date = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(MAX_DATE));
info->start_date = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(MAX_DATE));
FALLTHROUGH;
case 2:

View File

@ -178,7 +178,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
p->Send_string(""); // Used to be map-name.
p->Send_uint32(_settings_game.game_creation.generation_seed);
p->Send_uint8 (_settings_game.game_creation.landscape);
p->Send_uint32(TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
p->Send_uint32(static_cast<int32_t>(TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)));
p->Send_uint16(Map::SizeX());
p->Send_uint16(Map::SizeY());
@ -208,7 +208,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
{
Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE);
p->Send_uint32(TimerGameCalendar::date);
p->Send_uint32(static_cast<int32_t>(TimerGameCalendar::date));
this->SendPacket(p);
return NETWORK_RECV_STATUS_OKAY;
@ -244,7 +244,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC
p->Send_string(cs == nullptr ? "" : const_cast<NetworkAddress &>(cs->client_address).GetHostname());
p->Send_string(ci->client_name);
p->Send_uint8 (0); // Used to be language
p->Send_uint32(ci->join_date);
p->Send_uint32(static_cast<int32_t>(ci->join_date));
p->Send_uint8 (ci->client_playas);
this->SendPacket(p);
@ -329,7 +329,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
p->Send_string(GetString(STR_PRESIDENT_NAME));
p->Send_uint8 (c->colour);
p->Send_bool (NetworkCompanyIsPassworded(c->index));
p->Send_uint32(c->inaugurated_year);
p->Send_uint32(static_cast<int32_t>(c->inaugurated_year));
p->Send_bool (c->is_ai);
p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy

View File

@ -6512,18 +6512,18 @@ bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile)
{
switch (param) {
case 0x00: // current date
*value = std::max(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0));
*value = static_cast<int32_t>(std::max(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)));
return true;
case 0x01: // current year
*value = Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
*value = static_cast<int32_t>(Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR);
return true;
case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24)
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::Date start_of_year = TimerGameCalendar::ConvertYMDToDate(ymd.year, 0, 1);
*value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | (TimerGameCalendar::date - start_of_year) << 16;
*value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | static_cast<int32_t>(TimerGameCalendar::date - start_of_year) << 16;
return true;
}
@ -6629,11 +6629,11 @@ bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile)
return true;
case 0x23: // long format date
*value = TimerGameCalendar::date;
*value = static_cast<int32_t>(TimerGameCalendar::date);
return true;
case 0x24: // long format year
*value = TimerGameCalendar::year;
*value = static_cast<int32_t>(TimerGameCalendar::year);
return true;
default: return false;
@ -7228,7 +7228,7 @@ static uint32_t GetPatchVariable(uint8_t param)
{
switch (param) {
/* start year - 1920 */
case 0x0B: return std::max(_settings_game.game_creation.starting_year, ORIGINAL_BASE_YEAR) - ORIGINAL_BASE_YEAR;
case 0x0B: return static_cast<int32_t>(std::max(_settings_game.game_creation.starting_year, ORIGINAL_BASE_YEAR) - ORIGINAL_BASE_YEAR);
/* freight trains weight factor */
case 0x0E: return _settings_game.vehicle.freight_trains;

View File

@ -572,7 +572,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
}
case 0x48: return v->GetEngine()->flags; // Vehicle Type Info
case 0x49: return v->build_year;
case 0x49: return static_cast<int32_t>(v->build_year);
case 0x4A:
switch (v->type) {
@ -597,7 +597,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
}
case 0x4B: // Long date of last service
return v->date_of_last_service_newgrf;
return static_cast<int32_t>(v->date_of_last_service_newgrf);
case 0x4C: // Current maximum speed in NewGRF units
if (!v->IsPrimaryVehicle()) return 0;
@ -829,7 +829,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
case 0x41: return GB(ClampTo<uint16_t>(v->age), 8, 8);
case 0x42: return ClampTo<uint16_t>(v->max_age);
case 0x43: return GB(ClampTo<uint16_t>(v->max_age), 8, 8);
case 0x44: return Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
case 0x44: return static_cast<int32_t>(Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR);
case 0x45: return v->unitnumber;
case 0x46: return v->GetEngine()->grf_prop.local_id;
case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8);
@ -972,11 +972,11 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
}
}
case 0x48: return Engine::Get(this->self_type)->flags; // Vehicle Type Info
case 0x49: return TimerGameCalendar::year; // 'Long' format build year
case 0x4B: return TimerGameCalendar::date; // Long date of last service
case 0x49: return static_cast<int32_t>(TimerGameCalendar::year); // 'Long' format build year
case 0x4B: return static_cast<int32_t>(TimerGameCalendar::date); // Long date of last service
case 0x92: return ClampTo<uint16_t>(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date of last service
case 0x93: return GB(ClampTo<uint16_t>(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
case 0xC4: return Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year
case 0xC4: return static_cast<int32_t>(Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR); // Build year
case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
case 0xDA: return INVALID_VEHICLE; // Next vehicle

View File

@ -296,7 +296,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, Ho
case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2;
/* Building age. */
case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0;
case 0x41: return static_cast<int32_t>(IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0);
/* Town zone */
case 0x42: return GetTownRadiusGroup(this->town, this->tile);

View File

@ -163,7 +163,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo
switch (variable) {
case 0x80: return this->tile;
case 0x81: return GB(this->tile, 8, 8);
case 0x81: return GB(static_cast<uint32_t>(this->tile), 8, 8);
/* Pointer to the town the industry is associated with */
case 0x82: return this->industry->town->index;
@ -247,7 +247,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo
return this->industry->founder | (is_ai ? 0x10000 : 0) | (colours << 24);
}
case 0x46: return this->industry->construction_date; // Date when built - long format - (in days)
case 0x46: return static_cast<int32_t>(this->industry->construction_date); // Date when built - long format - (in days)
/* Override flags from GS */
case 0x47: return this->industry->ctlflags;
@ -338,7 +338,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo
if (!IsValidCargoID(cargo)) return 0;
auto it = this->industry->GetCargoAccepted(cargo);
if (it == std::end(this->industry->accepted)) return 0; // invalid cargo
if (variable == 0x6E) return it->last_accepted;
if (variable == 0x6E) return static_cast<int32_t>(it->last_accepted);
if (variable == 0x6F) return it->waiting;
NOT_REACHED();
}
@ -348,7 +348,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo
/* Industry structure access*/
case 0x80: return this->industry->location.tile;
case 0x81: return GB(this->industry->location.tile, 8, 8);
case 0x81: return GB(static_cast<uint32_t>(this->industry->location.tile), 8, 8);
/* Pointer to the town the industry is associated with */
case 0x82: return this->industry->town->index;
case 0x83:

View File

@ -277,7 +277,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte local_id, uint32_t grf
break;
/* Construction date */
case 0x42: return TimerGameCalendar::date;
case 0x42: return static_cast<int32_t>(TimerGameCalendar::date);
/* Object founder information */
case 0x44: return _current_company;
@ -315,7 +315,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte local_id, uint32_t grf
case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile);
/* Construction date */
case 0x42: return this->obj->build_date;
case 0x42: return static_cast<int32_t>(this->obj->build_date);
/* Animation counter */
case 0x43: return GetAnimationFrame(this->tile);

View File

@ -30,7 +30,7 @@
case 0x40: return 0;
case 0x41: return 0;
case 0x42: return 0;
case 0x43: return TimerGameCalendar::date;
case 0x43: return static_cast<int32_t>(TimerGameCalendar::date);
case 0x44: return HZB_TOWN_EDGE;
}
}
@ -40,8 +40,8 @@
case 0x41: return 0;
case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile);
case 0x43:
if (IsRailDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date;
return TimerGameCalendar::date;
if (IsRailDepotTile(this->tile)) return static_cast<int32_t>(Depot::GetByTile(this->tile)->build_date);
return static_cast<int32_t>(TimerGameCalendar::date);
case 0x44: {
const Town *t = nullptr;
if (IsRailDepotTile(this->tile)) {

View File

@ -30,7 +30,7 @@
case 0x40: return 0;
case 0x41: return 0;
case 0x42: return 0;
case 0x43: return TimerGameCalendar::date;
case 0x43: return static_cast<int32_t>(TimerGameCalendar::date);
case 0x44: return HZB_TOWN_EDGE;
}
}
@ -40,8 +40,8 @@
case 0x41: return 0;
case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile);
case 0x43:
if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date;
return TimerGameCalendar::date;
if (IsRoadDepotTile(this->tile)) return static_cast<int32_t>(Depot::GetByTile(this->tile)->build_date);
return static_cast<int32_t>(TimerGameCalendar::date);
case 0x44: {
const Town *t = nullptr;
if (IsRoadDepotTile(this->tile)) {

View File

@ -44,7 +44,7 @@
/* Town properties */
case 0x80: return this->t->xy;
case 0x81: return GB(this->t->xy, 8, 8);
case 0x81: return GB(static_cast<uint32_t>(this->t->xy), 8, 8);
case 0x82: return ClampTo<uint16_t>(this->t->cache.population);
case 0x83: return GB(ClampTo<uint16_t>(this->t->cache.population), 8, 8);
case 0x8A: return this->t->grow_counter / TOWN_GROWTH_TICKS;

View File

@ -430,7 +430,7 @@ struct AfterNewGRFScan : NewGRFScanCallback {
MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol);
SetEffectVolume(_settings_client.music.effect_vol);
if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", startyear);
if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", static_cast<int32_t>(startyear));
if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed;
if (!dedicated_host.empty()) {
@ -1389,7 +1389,7 @@ void StateGameLoop()
CallWindowGameTickEvent();
NewsLoop();
} else {
if (_debug_desync_level > 2 && TimerGameCalendar::date_fract == 0 && (TimerGameCalendar::date & 0x1F) == 0) {
if (_debug_desync_level > 2 && TimerGameCalendar::date_fract == 0 && (static_cast<int32_t>(TimerGameCalendar::date) & 0x1F) == 0) {
/* Save the desync savegame if needed. */
std::string name = fmt::format("dmp_cmds_{:08x}_{:08x}.sav", _settings_game.game_creation.generation_seed, TimerGameCalendar::date);
SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);

View File

@ -1922,6 +1922,12 @@ static bool OrderConditionCompare(OrderConditionComparator occ, int variable, in
}
}
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value)
{
return OrderConditionCompare(occ, static_cast<typename T::BaseType>(variable), value);
}
/**
* Process a conditional order and determine the next order.
* @param order the order the vehicle currently has

View File

@ -25,7 +25,7 @@ struct CYapfNodeKeyExitDir {
inline int CalcHash() const
{
return m_exitdir | (m_tile << 2);
return m_exitdir | (static_cast<uint32_t>(m_tile) << 2);
}
inline bool operator==(const CYapfNodeKeyExitDir &other) const
@ -45,7 +45,7 @@ struct CYapfNodeKeyTrackDir : public CYapfNodeKeyExitDir
{
inline int CalcHash() const
{
return m_td | (m_tile << 4);
return m_td | (static_cast<uint32_t>(m_tile) << 4);
}
inline bool operator==(const CYapfNodeKeyTrackDir &other) const

View File

@ -225,7 +225,7 @@ RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date
if (rti->label == 0) continue;
/* Not date introduced. */
if (!IsInsideMM(rti->introduction_date, 0, MAX_DATE)) continue;
if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE))) continue;
/* Not yet introduced at this date. */
if (rti->introduction_date > date) continue;

View File

@ -115,7 +115,7 @@ bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype)
if (rti->label == 0) return false;
/* Not yet introduced at this date. */
if (IsInsideMM(rti->introduction_date, 0, MAX_DATE) && rti->introduction_date > TimerGameCalendar::date) return false;
if (IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) return false;
/*
* Do not allow building hidden road types, except when a town may build it.
@ -173,7 +173,7 @@ RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date
if (rti->label == 0) continue;
/* Not date introduced. */
if (!IsInsideMM(rti->introduction_date, 0, MAX_DATE)) continue;
if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE))) continue;
/* Not yet introduced at this date. */
if (rti->introduction_date > date) continue;

View File

@ -169,7 +169,7 @@ struct MAP2ChunkHandler : ChunkHandler {
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
TileIndex size = Map::Size();
SlSetLength(size * sizeof(uint16_t));
SlSetLength(static_cast<uint32_t>(size) * sizeof(uint16_t));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m2();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
@ -344,7 +344,7 @@ struct MAP8ChunkHandler : ChunkHandler {
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
TileIndex size = Map::Size();
SlSetLength(size * sizeof(uint16_t));
SlSetLength(static_cast<uint32_t>(size) * sizeof(uint16_t));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m8();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);

View File

@ -93,9 +93,6 @@ struct OldChunks {
OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK
};
/* If it fails, check lines above.. */
static_assert(sizeof(TileIndex) == 4);
extern uint _bump_assert_value;
byte ReadByte(LoadgameState *ls);
bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks);

View File

@ -57,8 +57,8 @@ static void FixTTDMapArray()
/* _old_map3 is moved to _m::m3 and _m::m4 */
for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) {
Tile tile(t);
tile.m3() = _old_map3[t * 2];
tile.m4() = _old_map3[t * 2 + 1];
tile.m3() = _old_map3[static_cast<uint32_t>(t) * 2];
tile.m4() = _old_map3[static_cast<uint32_t>(t) * 2 + 1];
}
for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) {
@ -416,7 +416,7 @@ static bool FixTTOEngines()
if (TimerGameCalendar::date >= e->intro_date && HasBit(e->info.climates, 0)) {
e->flags |= ENGINE_AVAILABLE;
e->company_avail = MAX_UVALUE(CompanyMask);
e->age = TimerGameCalendar::date > e->intro_date ? (TimerGameCalendar::date - e->intro_date) / 30 : 0;
e->age = TimerGameCalendar::date > e->intro_date ? static_cast<int32_t>(TimerGameCalendar::date - e->intro_date) / 30 : 0;
}
} else {
/* Using data from TTO savegame */

View File

@ -63,5 +63,5 @@
{
if (!IsValidBaseStation(station_id)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)::BaseStation::Get(station_id)->build_date;
return (ScriptDate::Date)(int32_t)::BaseStation::Get(station_id)->build_date;
}

View File

@ -50,5 +50,5 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client)
{
NetworkClientInfo *ci = FindClientInfo(client);
if (ci == nullptr) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)ci->join_date;
return (ScriptDate::Date)(int32_t)ci->join_date;
}

View File

@ -22,7 +22,7 @@
/* static */ ScriptDate::Date ScriptDate::GetCurrentDate()
{
return (ScriptDate::Date)TimerGameCalendar::date;
return (ScriptDate::Date)(int32_t)TimerGameCalendar::date;
}
/* static */ SQInteger ScriptDate::GetYear(ScriptDate::Date date)
@ -31,7 +31,7 @@
::TimerGameCalendar::YearMonthDay ymd;
::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
return ymd.year;
return (int32_t)ymd.year;
}
/* static */ SQInteger ScriptDate::GetMonth(ScriptDate::Date date)
@ -58,7 +58,7 @@
if (day_of_month < 1 || day_of_month > 31) return DATE_INVALID;
if (year < 0 || year > MAX_YEAR) return DATE_INVALID;
return (ScriptDate::Date)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month);
return (ScriptDate::Date)(int32_t)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month);
}
/* static */ SQInteger ScriptDate::GetSystemTime()

View File

@ -31,7 +31,7 @@ public:
* compose valid date values for a known year, month and day.
*/
enum Date {
DATE_INVALID = ::INVALID_DATE, ///< A value representing an invalid date.
DATE_INVALID = (int32_t)::INVALID_DATE, ///< A value representing an invalid date.
};
/**

View File

@ -139,7 +139,7 @@
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
return ::Engine::Get(engine_id)->GetLifeLengthInDays();
return (int32_t)::Engine::Get(engine_id)->GetLifeLengthInDays();
}
/* static */ Money ScriptEngine::GetRunningCost(EngineID engine_id)
@ -179,7 +179,7 @@
{
if (!IsValidEngine(engine_id)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date;
return (ScriptDate::Date)(int32_t)::Engine::Get(engine_id)->intro_date;
}
/* static */ ScriptVehicle::VehicleType ScriptEngine::GetVehicleType(EngineID engine_id)

View File

@ -53,7 +53,7 @@
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)i->construction_date;
return (ScriptDate::Date)(int32_t)i->construction_date;
}
/* static */ bool ScriptIndustry::SetText(IndustryID industry_id, Text *text)
@ -222,7 +222,7 @@
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return 0;
return i->last_prod_year;
return (int32_t)i->last_prod_year;
}
/* static */ ScriptDate::Date ScriptIndustry::GetCargoLastAcceptedDate(IndustryID industry_id, CargoID cargo_type)
@ -232,11 +232,11 @@
if (!::IsValidCargoID(cargo_type)) {
auto it = std::max_element(std::begin(i->accepted), std::end(i->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
return (ScriptDate::Date)it->last_accepted;
return (ScriptDate::Date)(int32_t)it->last_accepted;
} else {
auto it = i->GetCargoAccepted(cargo_type);
if (it == std::end(i->accepted)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)it->last_accepted;
return (ScriptDate::Date)(int32_t)it->last_accepted;
}
}

View File

@ -182,7 +182,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type)
EnforcePrecondition(ScriptDate::DATE_INVALID, IsValidStoryPage(story_page_id));
EnforceDeityMode(ScriptDate::DATE_INVALID);
return (ScriptDate::Date)StoryPage::Get(story_page_id)->date;
return (ScriptDate::Date)(int32_t)StoryPage::Get(story_page_id)->date;
}
/* static */ bool ScriptStoryPage::SetDate(StoryPageID story_page_id, ScriptDate::Date date)

View File

@ -311,7 +311,7 @@
{
if (!IsValidVehicle(vehicle_id)) return -1;
return ::Vehicle::Get(vehicle_id)->age;
return (int32_t)::Vehicle::Get(vehicle_id)->age;
}
/* static */ SQInteger ScriptVehicle::GetWagonAge(VehicleID vehicle_id, SQInteger wagon)
@ -323,21 +323,21 @@
if (v->type == VEH_TRAIN) {
while (wagon-- > 0) v = ::Train::From(v)->GetNextUnit();
}
return v->age;
return (int32_t)v->age;
}
/* static */ SQInteger ScriptVehicle::GetMaxAge(VehicleID vehicle_id)
{
if (!IsPrimaryVehicle(vehicle_id)) return -1;
return ::Vehicle::Get(vehicle_id)->max_age;
return (int32_t)::Vehicle::Get(vehicle_id)->max_age;
}
/* static */ SQInteger ScriptVehicle::GetAgeLeft(VehicleID vehicle_id)
{
if (!IsPrimaryVehicle(vehicle_id)) return -1;
return ::Vehicle::Get(vehicle_id)->max_age - ::Vehicle::Get(vehicle_id)->age;
return (int32_t)(::Vehicle::Get(vehicle_id)->max_age - ::Vehicle::Get(vehicle_id)->age);
}
/* static */ SQInteger ScriptVehicle::GetCurrentSpeed(VehicleID vehicle_id)

View File

@ -149,12 +149,46 @@ struct IntSettingDesc : SettingDesc {
*/
typedef void PostChangeCallback(int32_t value);
IntSettingDesc(const SaveLoad &save, SettingFlag flags, bool startup, int32_t def,
int32_t min, uint32_t max, int32_t interval, StringID str, StringID str_help, StringID str_val,
template <
typename Tdef,
typename Tmin,
typename Tmax,
typename Tinterval,
std::enable_if_t<std::disjunction_v<std::is_convertible<Tdef, int32_t>, std::is_base_of<StrongTypedefBase, Tdef>>, int> = 0,
std::enable_if_t<std::disjunction_v<std::is_convertible<Tmin, int32_t>, std::is_base_of<StrongTypedefBase, Tmin>>, int> = 0,
std::enable_if_t<std::disjunction_v<std::is_convertible<Tmax, uint32_t>, std::is_base_of<StrongTypedefBase, Tmax>>, int> = 0,
std::enable_if_t<std::disjunction_v<std::is_convertible<Tinterval, int32_t>, std::is_base_of<StrongTypedefBase, Tinterval>>, int> = 0
>
IntSettingDesc(const SaveLoad &save, SettingFlag flags, bool startup, Tdef def,
Tmin min, Tmax max, Tinterval interval, StringID str, StringID str_help, StringID str_val,
SettingCategory cat, PreChangeCheck pre_check, PostChangeCallback post_callback) :
SettingDesc(save, flags, startup), def(def), min(min), max(max), interval(interval),
SettingDesc(save, flags, startup),
str(str), str_help(str_help), str_val(str_val), cat(cat), pre_check(pre_check),
post_callback(post_callback) {}
post_callback(post_callback) {
if constexpr (std::is_base_of_v<StrongTypedefBase, Tdef>) {
this->def = static_cast<typename Tdef::BaseType>(def);
} else {
this->def = def;
}
if constexpr (std::is_base_of_v<StrongTypedefBase, Tmin>) {
this->min = static_cast<typename Tmin::BaseType>(min);
} else {
this->min = min;
}
if constexpr (std::is_base_of_v<StrongTypedefBase, Tmax>) {
this->max = static_cast<typename Tmax::BaseType>(max);
} else {
this->max = max;
}
if constexpr (std::is_base_of_v<StrongTypedefBase, Tinterval>) {
this->interval = static_cast<typename Tinterval::BaseType>(interval);
} else {
this->interval = interval;
}
}
int32_t def; ///< default value given when none is present
int32_t min; ///< minimum values
@ -193,7 +227,7 @@ struct BoolSettingDesc : IntSettingDesc {
BoolSettingDesc(const SaveLoad &save, SettingFlag flags, bool startup, bool def,
StringID str, StringID str_help, StringID str_val, SettingCategory cat,
PreChangeCheck pre_check, PostChangeCallback post_callback) :
IntSettingDesc(save, flags, startup, def, 0, 1, 0, str, str_help, str_val, cat,
IntSettingDesc(save, flags, startup, def ? 1 : 0, 0, 1, 0, str, str_help, str_val, cat,
pre_check, post_callback) {}
static std::optional<bool> ParseSingleValue(const char *str);

View File

@ -126,6 +126,13 @@
# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#endif
#if defined(_MSC_VER)
// See https://learn.microsoft.com/en-us/cpp/cpp/empty-bases?view=msvc-170
# define EMPTY_BASES __declspec(empty_bases)
#else
# define EMPTY_BASES
#endif
/* Stuff for MSVC */
#if defined(_MSC_VER)
# pragma once

View File

@ -15,6 +15,7 @@
#include "gfx_type.h"
#include "core/bitmath_func.hpp"
#include "core/span_type.hpp"
#include "core/strong_typedef_type.hpp"
#include "vehicle_type.h"
/**
@ -82,6 +83,18 @@ void SetDParam(size_t n, uint64_t v);
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count = 0, FontSize size = FS_NORMAL);
void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL);
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
void SetDParam(size_t n, T v)
{
SetDParam(n, static_cast<typename T::BaseType>(v));
}
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
void SetDParamMaxValue(size_t n, T max_value, uint min_count = 0, FontSize size = FS_NORMAL)
{
SetDParamMaxValue(n, static_cast<typename T::BaseType>(max_value), min_count, size);
}
void SetDParamStr(size_t n, const char *str);
void SetDParamStr(size_t n, const std::string &str);
void SetDParamStr(size_t n, std::string &&str);

View File

@ -153,6 +153,12 @@ public:
this->parameters[n].string_view = nullptr;
}
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
void SetParam(size_t n, T v)
{
SetParam(n, static_cast<typename T::BaseType>(v));
}
void SetParam(size_t n, const char *str)
{
assert(n < this->parameters.size());

View File

@ -82,7 +82,7 @@ static const RoadTypeInfo _original_roadtypes[] = {
0x01,
/* introduction date */
MIN_YEAR,
static_cast<int32_t>(MIN_YEAR),
/* roadtypes required for this to be introduced */
ROADTYPES_NONE,

View File

@ -81,36 +81,13 @@ enum TropicZone {
/**
* The index/ID of a Tile.
*
* It is compatible with int32 / int64 for easy math throughout the code.
*/
struct TileIndex : StrongIntegralTypedef<uint32_t, TileIndex> {
using StrongIntegralTypedef<uint32_t, TileIndex>::StrongIntegralTypedef;
using TileIndex = StrongType::Typedef<uint32_t, struct TileIndexTag, StrongType::Implicit, StrongType::Compare, StrongType::Integer, StrongType::Compatible<int32_t>, StrongType::Compatible<int64_t>>;
debug_inline constexpr TileIndex() = default;
debug_inline constexpr TileIndex(const TileIndex &o) = default;
debug_inline constexpr TileIndex(TileIndex &&o) = default;
debug_inline constexpr TileIndex(const uint32_t &value) : StrongIntegralTypedef<uint32_t, TileIndex>(value) {}
debug_inline constexpr TileIndex &operator =(const TileIndex &rhs) { this->value = rhs.value; return *this; }
debug_inline constexpr TileIndex &operator =(TileIndex &&rhs) { this->value = std::move(rhs.value); return *this; }
debug_inline constexpr TileIndex &operator =(const uint32_t &rhs) { this->value = rhs; return *this; }
/** Implicit conversion to the base type for e.g. array indexing. */
debug_inline constexpr operator uint32_t() const { return this->value; }
/* Import operators from the base class into our overload set. */
using StrongIntegralTypedef::operator ==;
using StrongIntegralTypedef::operator !=;
using StrongIntegralTypedef::operator +;
using StrongIntegralTypedef::operator -;
/* Add comparison and add/sub for signed ints as e.g. 0 is signed and will
* match ambiguously when only unsigned overloads are present. */
constexpr bool operator ==(int rhs) const { return this->value == (uint32_t)rhs; }
constexpr bool operator !=(int rhs) const { return this->value != (uint32_t)rhs; }
constexpr TileIndex operator +(int rhs) const { return { (uint32_t)(this->value + rhs) }; }
constexpr TileIndex operator -(int rhs) const { return { (uint32_t)(this->value - rhs) }; }
};
/* Make sure the size is as expected. */
static_assert(sizeof(TileIndex) == 4);
/**
* The very nice invalid tile marker

View File

@ -75,8 +75,8 @@ static const uint16_t _accum_days_for_month[] = {
*/
/* There are 97 leap years in 400 years */
TimerGameCalendar::Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
int rem = date % (DAYS_IN_YEAR * 400 + 97);
TimerGameCalendar::Year yr = 400 * (static_cast<int32_t>(date) / (DAYS_IN_YEAR * 400 + 97));
int rem = static_cast<int32_t>(date) % (DAYS_IN_YEAR * 400 + 97);
uint16_t x;
if (rem >= DAYS_IN_YEAR * 100 + 25) {
@ -141,7 +141,7 @@ static const uint16_t _accum_days_for_month[] = {
*/
/* static */ bool TimerGameCalendar::IsLeapYear(TimerGameCalendar::Year yr)
{
return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
return static_cast<int32_t>(yr) % 4 == 0 && (static_cast<int32_t>(yr) % 100 != 0 || static_cast<int32_t>(yr) % 400 == 0);
}
/**
@ -215,7 +215,7 @@ void TimerManager<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed delta)
timer->Elapsed(TimerGameCalendar::DAY);
}
if ((TimerGameCalendar::date % 7) == 3) {
if ((static_cast<int32_t>(TimerGameCalendar::date) % 7) == 3) {
for (auto timer : timers) {
timer->Elapsed(TimerGameCalendar::WEEK);
}

View File

@ -11,6 +11,7 @@
#define TIMER_GAME_CALENDAR_H
#include "stdafx.h"
#include "../core/strong_typedef_type.hpp"
/**
* Timer that is increased every 27ms, and counts towards ticks / days / months / years.
@ -76,12 +77,18 @@ public:
struct TStorage {
};
using Date = int32_t; ///< The type to store our dates in
using DateFract = uint16_t; ///< The fraction of a date we're in, i.e. the number of ticks since the last date changeover
/** The type to store our dates in. */
using Date = StrongType::Typedef<int32_t, struct DateTag, StrongType::Explicit, StrongType::Compare, StrongType::Integer>;
using Year = int32_t; ///< Type for the year, note: 0 based, i.e. starts at the year 0.
using Month = uint8_t; ///< Type for the month, note: 0 based, i.e. 0 = January, 11 = December.
using Day = uint8_t; ///< Type for the day of the month, note: 1 based, first day of a month is 1.
/** The fraction of a date we're in, i.e. the number of ticks since the last date changeover. */
using DateFract = uint16_t;
/** Type for the year, note: 0 based, i.e. starts at the year 0. */
using Year = StrongType::Typedef<int32_t, struct YearTag, StrongType::Explicit, StrongType::Compare, StrongType::Integer>;
/** Type for the month, note: 0 based, i.e. 0 = January, 11 = December. */
using Month = uint8_t;
/** Type for the day of the month, note: 1 based, first day of a month is 1. */
using Day = uint8_t;
/**
* Data structure to convert between Date and triplet (year, month, and day).

View File

@ -426,7 +426,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
if (v->timetable_start != 0) {
v->lateness_counter = (TimerGameCalendar::date - v->timetable_start) * DAY_TICKS + TimerGameCalendar::date_fract;
v->lateness_counter = static_cast<int32_t>(TimerGameCalendar::date - v->timetable_start) * DAY_TICKS + TimerGameCalendar::date_fract;
v->timetable_start = 0;
}

View File

@ -2510,7 +2510,7 @@ struct ScenarioEditorToolbarWindow : Window {
value = atoi(str);
} else {
/* An empty string means revert to the default */
value = DEF_START_YEAR;
value = static_cast<int32_t>(DEF_START_YEAR);
}
SetStartingYear(value);

View File

@ -595,7 +595,7 @@ static void TileLoop_Town(TileIndex tile)
/* Binomial distribution per tick, by a series of coin flips */
/* Reduce generation rate to a 1/4, using tile bits to spread out distribution.
* As tick counter is incremented by 256 between each call, we ignore the lower 8 bits. */
if (GB(TimerGameTick::counter, 8, 2) == GB(tile, 0, 2)) {
if (GB(TimerGameTick::counter, 8, 2) == GB(static_cast<uint32_t>(tile), 0, 2)) {
/* Make a bitmask with up to 32 bits set, one for each potential pax */
int genmax = (hs->population + 7) / 8;
uint32_t genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1);
@ -871,7 +871,7 @@ RoadType GetTownRoadType(const Town *t)
if (!HasBit(rti->flags, ROTF_TOWN_BUILD)) continue;
/* Not yet introduced at this date. */
if (IsInsideMM(rti->introduction_date, 0, MAX_DATE) && rti->introduction_date > TimerGameCalendar::date) continue;
if (IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) continue;
if (best != nullptr) {
if ((rti->max_speed == 0 ? assume_max_speed : rti->max_speed) < (best->max_speed == 0 ? assume_max_speed : best->max_speed)) continue;

View File

@ -1400,7 +1400,7 @@ void AgeVehicle(Vehicle *v)
str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
} else if (age == DateAtStartOfYear(0)) {
str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
} else if (age > DateAtStartOfYear(0) && (age % DAYS_IN_LEAP_YEAR) == 0) {
} else if (age > DateAtStartOfYear(0) && (static_cast<int32_t>(age) % DAYS_IN_LEAP_YEAR) == 0) {
str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
} else {
return;